TL;DR — Key Takeaways

  • Enforce read-only access at both the MCP layer and the database.
  • Use a dedicated, non-owner database role with only the permissions the AI agent needs.
  • Test that approved reads succeed and prohibited writes fail.
  • Review inherited roles, public grants and effective privileges regularly.
  • Keep MCP credential revocation and database access revocation independent.
  • Correlate MCP request logs with database execution logs for stronger auditing.

Teams connecting AI agents to production data often start with a reassuring control: Mark the MCP server or tool as read-only. The label is useful, but it is not the final security boundary. A database connection with broad privileges can still turn a policy mistake into a production change.

The safer model is simple: Read-only access should be enforced twice. The MCP layer narrows what the client is allowed to request. The database independently narrows what the execution identity is allowed to do.

Read-Only is a Chain, Not a Switch

There are at least three permission layers in a typical MCP database workflow:

  • The AI client proves its identity to the MCP server.
  • The MCP server decides which tools and operations the client may use.
  • The database authorizes the role used to execute the final query.

The effective permission is the intersection of all three layers. Authentication answers who is calling. MCP policy answers which operation the caller may request. Database grants answer what the resulting session can actually execute.

Why the Database Must Have the Final Say

Tool-level restrictions are application controls. They depend on the server correctly classifying operations and applying policy to every path that can reach the database.

That control can fail in ordinary ways. A new tool may bypass an older permission check. A parser may classify a statement differently than expected. A stored procedure exposed as a read operation may produce side effects.

None of these possibilities means the MCP layer is useless. It means the database should not delegate its final authorization decision to another component.

If the database role can only connect, use a specific schema and select from approved tables, then an attempted write fails even if the request reaches the database.

Create a Dedicated Execution Identity

Do not connect an AI agent with an owner, migration or administrator account. Create a separate login role for the workload and grant it access to only the objects needed.

For PostgreSQL, a minimal pattern can look like this:

CREATE ROLE ai_reader LOGIN PASSWORD 'replace-with-a-secret';

GRANT CONNECT ON DATABASE app_production TO ai_reader;
GRANT USAGE ON SCHEMA reporting TO ai_reader;
GRANT SELECT ON TABLE
  reporting.daily_metrics,
  reporting.customer_health
TO ai_reader;

Granting access to selected tables makes the review surface smaller and prevents a newly created sensitive table from becoming readable by accident. Broader schema access may be appropriate, but it should be a documented decision.

Test Denial, Not Only Success

Most connection checks prove that a query works. A security check must also prove that a forbidden query fails.

After configuring the execution identity, run one expected read and one harmless write attempt in a controlled test object or within a transaction:

SELECT * FROM reporting.daily_metrics LIMIT 1;

BEGIN;
UPDATE reporting.daily_metrics
SET metric_value = metric_value
WHERE false;
ROLLBACK;

The read should succeed. The update should be rejected because the role lacks theUPDATE, even though the statement would not change a row.

This test catches a common configuration error: The MCP interface says read-only, but the database credential belongs to a role with write access. Repeat it after permission changes, migrations, credential rotation or MCP server upgrades.

Check Effective Privileges

Security reviews should inspect effective access, not only the grants someone remembers creating. Roles can inherit permissions through memberships, ownership, default privileges or public grants.

In PostgreSQL, teams can review role memberships and object privileges with catalog queries and information_schema views. The review should answer:

  • Can the role create objects in any reachable schema?
  • Can it insert, update, delete, truncate or execute privileged functions?
  • Does it inherit access from another role?
  • Can it read tables outside the intended scope?
  • Can it change its own role or session authorization?

Run these checks using the same login identity and connection path used by the MCP server. An administrator session can hide differences in inherited privileges and row-level security behavior.

Keep Revocation Independent

Incident response should not depend on a single control plane. Teams should be able to disable the MCP credential and revoke the database role separately.

At the MCP layer, revoke the client key, OAuth grant or server link. At the database layer, block new sessions and terminate existing ones if the situation requires immediate containment.

For PostgreSQL, a basic emergency action can start with:

ALTER ROLE ai_reader NOLOGIN;

That prevents new connections. Existing sessions may need to be terminated separately. Document and test the procedure before an incident.

Log Both the Request and the Execution

MCP activity logs and database logs answer different questions.

The MCP layer can record the authenticated client, requested tool, policy decision, connection and response status. The database can record the execution identity, statement, duration and server-side error. Correlation identifiers, timestamps and stable connection identifiers help connect the two views.

A Practical Production Checklist

Before giving an AI agent access to a production database, verify the following:

  • The MCP client has its own revocable identity.
  • The MCP policy exposes only the required tools and operations.
  • The database uses a dedicated non-owner login role.
  • The role has access only to the required schemas, tables and operations.
  • One allowed read succeeds through the real MCP path.
  • One forbidden write fails at the database boundary.
  • Effective privileges and inherited role memberships are reviewed.
  • MCP and database activity can be correlated.
  • Gateway revocation and database revocation are documented separately.

A read-only label is useful because it communicates intent and reduces the operations available to the client. Production safety comes from turning that intent into independent enforcement. When both the MCP layer and the database agree, a mistake in one layer is less likely to become a change in production data.

Frequently Asked Questions

Why is an MCP read-only setting not enough?
Because it is an application-level control. A policy error, misclassified query or newly added tool could still reach the database. Database permissions provide an independent final barrier.
How can access be revoked during an incident?
Revoke the MCP client credential and disable the database role separately. In PostgreSQL, ALTER ROLE ai_reader NOLOGIN; prevents new sessions, while existing sessions may need to be terminated.
What should MCP and database logs record?
MCP logs should capture the client identity, requested tool and policy decision. Database logs should record the execution role, statement, duration and server-side errors. Correlation IDs help connect both records.