Permission Levels
The six permission codes and the operations each one allows. Quick reference matrix.
The six values that can appear in a permissions: baseline or per-table override. Use this page to look up exactly which operations a code grants. For the conceptual walk-through, see Permissions.
The matrix
| Code | SELECT | EXPLAIN | INSERT | UPDATE | DELETE | DDL¹ |
|---|---|---|---|---|---|---|
| R | ✓ | ✓ | ||||
| W | ✓ | ✓ | ✓ | |||
| RW | ✓ | ✓ | ✓ | ✓ | ✓ | |
| RA | ✓ | ✓ | ✓ | |||
| RWA | ✓ | ✓ | ✓ | ✓ | ||
| A | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
¹ DDL covers CREATE, DROP, ALTER, TRUNCATE, GRANT, REVOKE, and equivalent schema-mutation operations across every supported query language (e.g. MongoDB dropCollection, Elasticsearch index template ops, Cypher index/constraint creation, DynamoDB CreateTable).
What each code is for
- R — the safe default. Pick this when an agent should look but never touch.
- W — narrow write surface. Useful for dedicated audit / event tables where the agent should only append. Note that
WexcludesSELECT, so an agent withWon a table cannot read what it just wrote. - RW — the trusted baseline. Pick this for working tables where an agent will both read state and update it.
- RA — append-only with read. The right shape for log tables, event streams, and immutable-history patterns: agents can record new entries and read them back, but cannot retroactively edit or delete.
- RWA — write-with-update, no delete. For tables where rows can be added or amended but never removed (think soft-delete schemas, financial ledgers).
- A — admin. Everything plus DDL. Reserve for development, schema migrations, or trusted operational tooling. Granting
Ais a deliberate choice — see the warning on Permissions.
Operation mapping per database family
The matrix above uses SQL verbs. Other query languages map onto the same operation classes:
| Operation class | SQL | MongoDB | Cypher | Elasticsearch / OpenSearch | Vector (Weaviate, Qdrant, Milvus, Pinecone) | DynamoDB |
|---|---|---|---|---|---|---|
| SELECT | SELECT | find, findOne, aggregate, count, distinct | MATCH ... RETURN | _search, _count | query, fetch, scroll, count, recommend | Query, Scan, GetItem, BatchGetItem |
| INSERT | INSERT | insertOne, insertMany | CREATE, MERGE | _doc, _create | upsert, insert | PutItem, BatchWriteItem (put) |
| UPDATE | UPDATE | updateOne, updateMany, replaceOne | SET | _update | update | UpdateItem |
| DELETE | DELETE | deleteOne, deleteMany | DELETE, DETACH DELETE, REMOVE | _delete_by_query | delete | DeleteItem |
| DDL | CREATE/DROP/ALTER/TRUNCATE | dropCollection, createIndex, dropCollection | CREATE INDEX, DROP CONSTRAINT | _template, mapping mutations | create_collection, delete_collection | CreateTable, DeleteTable, UpdateTable |
If a query touches multiple tables (via JOIN, $lookup, _reindex, Cypher rebound labels, etc.), every touched target is checked independently with the operation it requires.
Special cases
No none value
There is no none access level. To deny reads on a specific table while leaving the database otherwise readable, set the table's override to W (write-only). To deny everything, don't connect the database to faz, or restrict access at the database role level outside faz. See Blocking a table from reads.
Implicit fallback
If the request is authenticated and a query target has no matching permission row, an implicit R is granted for that single target. This means undeclared databases and undeclared tables on declared databases default to read-only. See What happens to tables you didn't declare.
The * wildcard in audit logs
Internally, the per-database baseline is stored as a permission row with table_name = "*". You'll see this in faz policy output and in audit log entries. You don't write * in faz.yaml; the parser produces it from the access: field on each database entry.
Related
- Permissions — the conceptual model and the layered lookup.
faz.yaml— the full config schema.- How faz protects you — where the gate sits in the safety pipeline.