Privileges and the reader and contributor pattern
In this lesson you will
- Name the privileges you use daily and their prerequisites
- Explain inheritance and why the schema is the right level
- Apply the reader and contributor group per schema pattern
- Handle sensitive tables with separate schemas or table-level groups
Grant to the schema, through two groups
You now have a namespace and identities. This lesson connects them. The pattern we use on every platform is short: for every schema, one reader group and one contributor group, and a group as owner. People get access by joining a group, and nobody gets a grant of their own.
We cover the privileges you need, how inheritance works, and why the schema is the right level. We do not cover metastore-level privileges in depth.
The privileges that matter
The Unity Catalog documentation defines each privilege. These are the ones you use daily.
| Privilege | Allows | Also needs |
|---|---|---|
USE CATALOG | Interact with objects in a catalog. It gives no data access by itself | Granted by the catalog owner or a holder of MANAGE |
USE SCHEMA | The schema-level equivalent | USE CATALOG on the parent |
SELECT | Query a table, view or materialised view | USE CATALOG and USE SCHEMA |
MODIFY | Insert, update and delete data in a table | SELECT on the table, plus the usage privileges |
CREATE TABLE | Create tables or views in a schema | The documentation recommends granting it at schema level, with the usage privileges |
READ VOLUME | Read files in a volume | USE CATALOG and USE SCHEMA |
WRITE VOLUME | Add, remove or change files in a volume | The same |
EXECUTE | Call a function or load a registered model for inference | Grant it on individual functions and models |
MANAGE | Manage privileges, transfer ownership, rename and drop without being the owner | Not included in ALL PRIVILEGES |
Two points trip up most teams. First, usage privileges are required in addition to the data privilege. A group with SELECT on a table but no USE SCHEMA sees nothing. Second, MODIFY requires SELECT, so a contributor must also be a reader.
Inheritance: why the schema is the level
Privileges granted on a catalog or schema apply to its current and future child objects. The documentation gives the example that granting SELECT on a schema covers every existing and new table and view in it. The same applies to MODIFY, READ VOLUME, WRITE VOLUME and EXECUTE. MANAGE on a container also gives MANAGE on its children. The documentation also notes that inheritance requires privilege model version 1.0, so older metastores may need an upgrade first.
That behaviour makes the schema the natural level for grants:
- A grant on a table needs repeating for every new table, and people forget.
- A grant on a catalog is wide: it reaches every schema, including the ones you add next year.
- A grant on a schema matches a layer or a subject area. A new table in
goldis covered the moment it exists.
Grant on a table or volume only when one object has a different audience from the rest of its schema, such as a table with salary data. Our standard adds a table-level group for those cases.
The reader and contributor pattern
For every schema, create two groups.
| Group | Privileges on the schema | Who belongs to it |
|---|---|---|
...-reader | USE CATALOG on the catalog, USE SCHEMA, SELECT, READ VOLUME | Analysts, dashboards, downstream pipelines |
...-contributor | Everything the reader has, plus MODIFY, CREATE TABLE, WRITE VOLUME | The pipeline service principal that writes this layer |
...-owner | Ownership of the schema | A small platform group, never a person |
Pipelines that write silver are members of the silver contributor group and the bronze reader group. Analysts are members of the gold reader group. Nobody except the ingestion principal is a member of any bronze contributor group. The layers of lesson 1 and the groups line up one to one, so the access model explains itself.
Here is the SQL for one schema. Group names follow the convention from lesson 2.
Illustration
-- Reader: may see and query everything in prd_finance.gold, present and future.
GRANT USE CATALOG ON CATALOG prd_finance TO `grp-uc-prd-finance-gold-reader`;
GRANT USE SCHEMA ON SCHEMA prd_finance.gold TO `grp-uc-prd-finance-gold-reader`;
GRANT SELECT ON SCHEMA prd_finance.gold TO `grp-uc-prd-finance-gold-reader`;
GRANT READ VOLUME ON SCHEMA prd_finance.gold TO `grp-uc-prd-finance-gold-reader`;
-- Contributor: reads like the reader, and may also create and change tables and files.
GRANT USE CATALOG ON CATALOG prd_finance TO `grp-uc-prd-finance-gold-contributor`;
GRANT USE SCHEMA ON SCHEMA prd_finance.gold TO `grp-uc-prd-finance-gold-contributor`;
GRANT SELECT ON SCHEMA prd_finance.gold TO `grp-uc-prd-finance-gold-contributor`;
GRANT MODIFY ON SCHEMA prd_finance.gold TO `grp-uc-prd-finance-gold-contributor`;
GRANT CREATE TABLE ON SCHEMA prd_finance.gold TO `grp-uc-prd-finance-gold-contributor`;
GRANT WRITE VOLUME ON SCHEMA prd_finance.gold TO `grp-uc-prd-finance-gold-contributor`;
-- Ownership belongs to a group.
ALTER SCHEMA prd_finance.gold OWNER TO `grp-uc-prd-finance-gold-owner`;Run grants like this through your pipeline, from code. In lesson 7 the same pattern becomes a Terraform module, so nobody types a GRANT by hand in production.
Inspect and revoke
SHOW GRANTS ON SCHEMA prd_finance.gold; -- everything granted on this schema
SHOW GRANTS `grp-uc-prd-finance-gold-reader` ON SCHEMA prd_finance.gold;
REVOKE CREATE TABLE ON SCHEMA prd_finance.gold FROM `grp-uc-prd-finance-gold-contributor`;The documentation notes that REVOKE succeeds even if the privilege was never granted, so it is safe to run in cleanup scripts, and equally safe to mistype. Read the output of SHOW GRANTS afterwards.
Sensitive tables need their own audience
Suppose gold.payroll must be visible to HR only. Keep the schema reader grant for general tables, and either place payroll in its own schema, such as gold_hr, or give it a table-level group. A separate schema is cleaner: the grants stay at schema level, and the inheritance works for you. If you must keep payroll in gold, the reader grant on the schema would expose it. That is why we design the schema boundaries around audiences, not only around layers.
Review access every quarter
Remove permissions nobody uses. Once a quarter, list the members of each group and the grants of each schema, and ask the owner to confirm both. Because access flows through groups, the review is a list of group members, not thousands of individual grants. System tables help (lesson 5), since they show what a group actually used.
Common mistakes
- Missing
USE SCHEMA. The classic "I cannot see my table". - Granting to a person "just for today". It stays for years.
- Grants on the catalog when a schema was meant.
ALL PRIVILEGESas a shortcut. It grants more than the job needs and hides intent.- Owner is the engineer who created the object. Change ownership to the group.
Summary
Grant on the schema, to two groups per schema, and let inheritance cover future tables. Remember the usage privileges. Give ownership to a group. Handle exceptions with separate schemas or table-level groups, and review quarterly.
Next lesson: finer control inside a table with row filters and column masks.
The idea in one picture
Reader and contributor per schema
- Entra ID groups
- Reader groupUSE, SELECT, READ VOLUME
- Contributor groupPlus MODIFY, CREATE TABLE
- SchemaFuture tables covered
- Owner group
Knowledge check
Answer each question. You see the reason behind every answer at once.
0 of 4 answered
Hands-on lab
Goal. Generate the GRANT script for a list of schemas and check it against the pattern.
Where to run it
Local Python Run this lab on your own machine with Python 3.10 or newer in a virtual environment.
Steps
- Write schemas.json with four schemas: bronze, silver, gold and gold_hr in two catalogs.
- Write generate_grants.py that prints, per schema, the reader and contributor statements from the lesson and ALTER statements for ownership by a group.
- Write a checker that reads the output and fails when a statement lacks USE CATALOG or USE SCHEMA, grants to a person, or gives MODIFY without SELECT.
- Break one generated statement by hand and confirm that the checker fails.
Expected result
A generated script for all schemas, a checker that passes it and a checker that fails the broken version with a clear message.
Go deeper
Official documentation and recommended courses from the providers.
- Databricks
- Free with an account
- Databricks Academy account
- Beginner
Databricks Fundamentals
The quickest way to confirm the platform basics before any role course, with a badge at the end.
Open course : Databricks Fundamentals. Opens the provider site in a new tab
- docs.databricks.com
Manage privileges
Open documentation : Manage privileges. Opens at the provider
- docs.databricks.com
Privilege types
Read at NexOps
Articles from our own projects on the same topic.
Sources
Last verified 2026-11-11
We check every source against the official documentation. Products change, so confirm details there before you build.