The six clauses every agent access policy needs
A production database access policy for AI agents needs six clauses: a unique identity per agent, an explicit table and operation scope, approval thresholds for risky actions, logging requirements, a revocation procedure, and an escalation path. Write one policy record per agent, phrase every clause as a testable statement, and treat the document as an engineering artifact that maps one-to-one onto grants and gateway rules. This is an engineering checklist, not legal advice: if your industry has regulatory obligations, involve counsel as well.
Most teams already have an access policy for humans. It usually says something like "production access requires a ticket, credentials are personal, and admin actions are reviewed." That policy quietly assumes the principal can be interviewed, disciplined, and trusted to hesitate. An AI agent is a non-human principal: it executes at machine speed, never hesitates, and will act on whatever text reaches its context window, including text an attacker planted. The moment agents hold credentials, the human policy stops covering your riskiest principal, and you need a document that does.
The rest of this post walks the six clauses, gives you a copy-paste template, and shows what the policy looks like when it lands in Postgres.
The policy as a gate: the six clauses define which agent operations reach the database and which are denied.
Walking the six clauses
1. Identity per agent. Every agent gets its own named principal: its own database role, its own API credential, its own entry in your inventory. No shared "automation" user, and never the application's connection string. Identity is the clause everything else hangs on, because scope, logging, and revocation all attach to a principal. If two agents share a login, you can revoke neither one alone and attribute nothing to either. Why grants alone are not the whole story is covered in read-only isn't enough.
2. Table and operation scope. Name the schemas and tables the agent may touch and the operations it may perform on each, and state that everything else is denied. "Read access to reporting tables" is a policy statement; "access as needed" is not. Scope should be written in terms the database can enforce: SELECT on these objects, INSERT on those, nothing on the rest. PostgreSQL's privilege system supports exactly this granularity through GRANT and REVOKE on individual tables (PostgreSQL docs).
3. Approval thresholds. Define which operations run autonomously and which pause for a human. A useful default: bounded reads run freely; schema changes, bulk writes, and anything touching tables tagged sensitive require a named approver before execution. Put numbers on it where you can (rows affected, tables touched) so the threshold is mechanical, not a vibe. The design of that approval gate, and how to keep it from becoming a bottleneck, is its own topic: see human-in-the-loop database migrations.
4. Logging requirements. State what gets recorded for every operation: the agent identity, the exact statement, the objects touched, the decision (allowed, denied, or approved and by whom), and a timestamp. State where the log lives and how long it is kept. If you deploy agents in the EU, note that the AI Act's Article 26 requires deployers of high-risk AI systems to keep automatically generated logs for at least six months (EU AI Act, Article 26); even outside that regime, six months is a sane floor. Why that record has to live outside the agent itself, and what a tamper-evident version looks like, is covered in audit trails for AI agents.
5. Revocation. Write down, in advance, how access is removed and how fast. Credential expiry should be automatic: in Postgres, CREATE ROLE ... VALID UNTIL puts a hard expiry date on a password at creation time (PostgreSQL docs). The policy should also name a kill switch: the single command or console action that severs the agent's connectivity immediately, and who is allowed to pull it. If revoking an agent requires a change request, you do not have revocation, you have a suggestion.
6. Escalation. Define what happens when the policy is violated or nearly violated: who gets paged when a denied operation fires, what counts as an incident versus noise, and when the default response is to suspend the agent rather than investigate while it keeps running. Agents fail at machine speed, so the escalation clause should bias toward stopping first and asking questions second.
The copy-paste template
Tool-agnostic AI agent database access policy template. One record per agent. Replace the bracketed values, delete nothing without a reason, and store it next to your infrastructure code so changes go through review.
# AI Agent Database Access Policy: one record per agent
# Engineering checklist. Not legal advice.
agent:
name: [agent-name, e.g. support-copilot]
owner: [team or person accountable]
purpose: [one sentence: what this agent does and why it needs data access]
principal: [dedicated credential, e.g. db role "agent_support_copilot"]
shared_credentials: forbidden
scope:
databases: [list]
allowed:
- object: [schema.table or pattern]
operations: [SELECT | INSERT | UPDATE | DELETE | DDL]
conditions: [row limits, column exclusions, tenant filters]
default: deny # anything not listed above is denied
approval:
autonomous: [e.g. SELECT under 10000 rows on non-sensitive tables]
requires_human:
- all DDL (schema changes)
- writes affecting more than [N] rows
- any operation on tables tagged [sensitive-tag]
approvers: [named role or group, not an individual]
approval_record: [where approvals are stored]
logging:
record_per_operation:
- agent identity and session id
- exact statement or operation
- objects touched and rows affected
- decision: allowed | denied | approved_by [who]
- timestamp (UTC)
destination: [append-only store, outside the agent's reach]
retention: [>= 6 months]
revocation:
credential_expiry: [max lifetime, e.g. 90 days, auto-enforced]
kill_switch: [exact command or console action]
kill_switch_owners: [who may execute it]
max_time_to_revoke: [target, e.g. 5 minutes]
escalation:
on_denied_operation: [alert channel and severity]
on_repeated_denials: [suspend agent pending review]
on_sensitive_data_access: [page on-call, open incident]
review_cadence: [re-review this policy every N days]
Every line in that template is checkable. That is the test of a good policy clause: someone can look at the running system and say true or false, the system matches the document.
Landing the policy in Postgres
The template is database-agnostic on purpose, but here is what clauses one, two, and five look like when they hit a Postgres instance. Any engine with roles and grants can express the same shape.
-- Clause 1: identity per agent, with clause 5's expiry built in CREATE ROLE agent_support_copilot LOGIN VALID UNTIL '2026-10-13'; -- credential auto-expires in 90 days -- Clause 2: explicit scope, default deny REVOKE ALL ON ALL TABLES IN SCHEMA public FROM agent_support_copilot; GRANT SELECT ON support.tickets, support.ticket_messages TO agent_support_copilot; GRANT SELECT, INSERT ON support.ticket_tags TO agent_support_copilot; -- Clause 5: the kill switch -- REVOKE CONNECT ON DATABASE app FROM agent_support_copilot;
Clauses three, four, and six do not fit inside the engine, and that is the honest limit of grants: Postgres can say what a role may do, but it cannot pause a statement for approval, attach an approver's name to it, or page anyone when a denied operation fires. Those clauses need something on the connection path in front of the database.
A policy the agent can read is not enforcement
One failure mode deserves its own warning. Teams sometimes implement the policy by pasting it into the agent's system prompt: "you may only run SELECT on the support schema." That is documentation. It enforces nothing. Prompt injection is the top entry in the OWASP Top 10 for LLM Applications because models cannot reliably separate trusted instructions from untrusted input in the same context window (OWASP LLM01), so any rule the agent can read is a rule a crafted input can talk it out of.
The policy document defines the boundary. The database grants and a gateway on the connection path enforce it, outside anything the agent's context can influence. How those two enforcement layers fit together is the subject of safe AI agent access to production databases; this post is about getting the boundary written down well enough that there is something coherent to enforce.
Keep the document alive
Two habits keep the policy from rotting. First, re-review on a schedule (the review_cadence line exists for a reason): agents gain capabilities, schemas grow, and a scope that was tight in March is stale by September. Second, treat every denied operation as data. A denial either caught a real overreach, in which case the escalation clause did its job, or it blocked legitimate work, in which case the scope clause needs a deliberate, reviewed amendment. Either way the document moves, and it moves through review rather than through someone quietly widening a grant.
Where Datapace fits
Datapace is building the context layer for AI on databases: a semantic layer that gives agents what's there, what it means, and how it connects, with a policy gate in front of the data so clauses like scope, approval thresholds, and logging are enforced on the connection path rather than trusted to the agent's prompt. If you are writing this policy for your own team, we would like to compare notes: start at datapace.ai or book a call.