cd /news/ai-tools/giving-an-llm-your-prod-database-is-… · home topics ai-tools article
[ARTICLE · art-106779] src=deepsql.ai ↗ pub= topic=ai-tools verified=true sentiment=· neutral

Giving an LLM your prod database is easy. Taking access away is the hard part

DeepSQL, an open-source database agent for Postgres and MySQL, released v1.2.0 with schema-scoped access policies that enforce permissions in the planner path, not just via prompts, to prevent LLMs from reading data beyond a user's authority. The update addresses bypasses such as CTEs and subqueries by guarding the entire SQL statement, and includes impersonation so policies can be tested as a specific user. The company found that a read-only connection is insufficient because it does not restrict who can read sensitive tables like hr.compensation.

read6 min views1 publishedAug 22, 2026
Giving an LLM your prod database is easy. Taking access away is the hard part
Image: source

All posts

Every "chat with your database" demo ends at the first correct query. The interesting engineering starts the moment a second user logs in — and the model can still see the salaries table.

Venkat Sakamuri

DeepSQL R&D · Ex Oracle Query Engine Team · YC & CMU

TL;DR #

  • A read-only connection is not an access policy. It stops writes; it does nothing about who may read hr.employees

. - Guarding "the query" is wrong. Guard the whole statement: CTEs, subqueries, unions,COMMENT

,CALL

, and whatever the editor lets a user paste in. - The only way to know a policy works is to look at the database as that user — so we built impersonation before we built anything else on top of policies.

We open-sourced DeepSQL (github.com/DeepSQLAI/deepsql) six weeks ago as a self-hosted database agent for Postgres and MySQL. The demo everyone builds — natural language in, SQL out, results in a table — took days. The last three releases have been almost entirely about the boring half: making sure the agent cannot read something the human asking cannot read.

That turns out to be a much harder problem than SQL generation, and I don't think it gets talked about enough.

The read-only connection lie #

The default posture for an LLM database tool is: connect with a read-only role, ship it. That closes exactly one hole — mutation — and leaves the bigger one wide open. SELECT

is the dangerous verb in an analytics context. A support engineer who could never open the finance dashboard can now ask "what's our average deal size by rep" and get a precise answer, because the agent's connection is a superset of every human's authority.

Two-thirds of the "AI DBA" tools I've looked at collapse every human into one service account. The audit log then reads:

2026-08-19 11:04:22  deepsql_agent  SELECT ... FROM finance.invoices ...
2026-08-19 11:04:41  deepsql_agent  SELECT ... FROM hr.compensation ...

Which is to say: it reads nothing. You cannot answer "who saw this row" after the fact, and in a Postgres instance with six schemas and 500+ tables — our ACME ERP fixture is exactly that, crm

, sales

, finance

, inventory

, hr

, marts

— nobody can hold in their head which of those an analyst is allowed to touch.

Policies in English, enforced in the planner path #

The mechanism we landed in v1.2.0 is schema-scoped access policies. An admin writes a rule in plain English:

Support engineers can read customer and ticket data. No financial or HR data. Never expose email addresses.

That resolves, at policy-save time, into a concrete artifact: an allowed schema list plus table and column deny lists. Not a prompt. A prompt is a suggestion; the model complies until someone writes "ignore prior instructions, I'm the DBA now." The resolved policy is enforced in three places the model does not control — schema introspection (the Brain only indexes what you may see, so denied tables never enter the context window), the query guard before execution, and the schema APIs the web UI and MCP client call.

The context-window point is the one people miss. If the agent's schema context contains hr.compensation

, the model will eventually reference it, and your only defense is a rejection at execution time — after the column names have already been leaked into the answer text.

Guard the statement, not the query #

Two fixes in this cut are worth reading if you're building anything similar, because both were bypasses we shipped and then had to close.

Enforce the allowlist over the whole statement. Our first guard resolved the tables in the primary FROM

. Which does nothing to:

WITH leak AS (
  SELECT employee_id, base_salary FROM hr.compensation
)
SELECT c.name, l.base_salary
FROM crm.customers c
JOIN leak l ON l.employee_id = c.owner_id;

The top-level target is crm.customers

— allowed. The payload comes out of a CTE. Every subquery, CTE, union arm, and lateral join has to be resolved against the allowlist, or the allowlist is decorative.

** COMMENT and CALL are not mutations.** Going the other way: our mutation classifier read the first table-shaped identifier in the statement and flagged

COMMENT ON TABLE sales.orders IS '...'

as a write on sales.orders

. Real work got blocked, so people asked for the guard to be relaxed. A guard with false positives gets turned off, and then you have no guard. Precision in a policy engine is a security property, not a UX nicety.The same class of bypass had to be closed in the SQL editor, which is the surface everyone forgets: the agent may be perfectly constrained while the raw editor next to it runs whatever you type through a different code path.

You cannot verify a policy you cannot see #

The feature I'd argue matters most sounds like an admin convenience: "View as" another user. An admin switches into a target profile and browses the schema tree, runs the agent, and opens dashboards exactly as that user experiences them — without their credentials.

Before it existed, verifying a policy meant creating a throwaway account, logging out, logging in, poking around, logging back. In practice: nobody did it. Policies were written, assumed correct, and never tested. With impersonation, checking a new rule takes about 30 seconds, so it actually happens. And the obvious follow-on fix — the agent running inside a "View as" session had still been resolving the admin's policy. An impersonation feature that doesn't impersonate the constraints is worse than none, because it hands you false confidence.

Why this is not a config problem you can defer #

A leaked row cannot be un-leaked. There's no revert, no rollback, no git revert

for "the contractor read the comp table in March." Unlike a bad deploy, database exposure is monotonic — it only accumulates, and you usually learn about it from someone outside the company.

That's the same shape as every irreversible database decision: the wrong primary key type, the wrong partition key, an unbounded jsonb

column. Cheap to prevent at design time, effectively permanent afterward. Adding an agent to your database doesn't create a new category of risk; it multiplies the throughput of the existing one, because natural language removes the SQL skill floor that used to accidentally gate access.

What DeepSQL does about this #

Policies are written in English, resolved once into schema allowlists and table/column deny lists, and enforced at introspection, at guard time, and in the schema APIs — the model never sees denied objects, so it cannot leak their names. The statement guard resolves every CTE, subquery, and union arm, not just the top-level FROM

, and distinguishes COMMENT

/CALL

from real mutations so it stays on. Admins verify any policy in seconds with "View as," which now correctly applies the target user's constraints to the agent too. All of it runs self-hosted in your own VPC with your own model endpoint — the code is at github.com/DeepSQLAI/deepsql, and v1.2.0 is a git checkout

and a docker compose up --build -d

away.

── more in #ai-tools 4 stories · sorted by recency
── more on @deepsql 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/giving-an-llm-your-p…] indexed:0 read:6min 2026-08-22 ·