"I doubt first-time users will trust a random tool and grant it database-level access with a curl command." That was the top objection on DeepSQL's Show HN in July 2026 — a self-hostable AI agent that does DBA work against Postgres and MySQL instances you operate — and it is the entire debate in one sentence. An agent that triages slow queries, recommends indexes, and watches your schema needs credentials to production data, and "database-level access" covers a very wide range of sins.
Here is the answer up front, before the story earns it: never hand the agent superuser. Give it a dedicated login role that owns nothing, point its read traffic at a replica, and let it change things only by writing migration files a human or CI pipeline applies. The five-rung ladder in this post shows the exact Postgres and MySQL grants for each step, plus what breaks when you skip one.
What DeepSQL actually is
DeepSQL launched on Hacker News in July 2026 with 52 points and 35 comments. Founder Venkat — Stayflexi (YC), CMU CS, ex-Oracle query engine team — built it as an internal tool after his own databases started bottlenecking 13,000+ hotels in production, then released it. The pitch is an agent that operates a database the way a senior DBA and data engineer would: fix slow queries (the team claims it cut its own Aurora spend from $9K to $3K a month), fix schema bloat, generate BI dashboards, and redact PII so the whole org can query safely.
Under the hood it runs about 20 background jobs that watch schema changes and bottlenecks, builds a "brain" from your codebase, rules, and query logs, and surfaces through a Web UI, CLI, MCP servers for Claude, Codex, and Cursor, Slack, and a daily digest email. Notably for everything below, its own worked traces show generated SQL executed on a read replica, not the primary.
The launch thread is also a case study in how fast trust gets negotiated. Commenters found no GitHub link and a closed codebase behind the "self-hostable" label; the founder promised open source by month end, and the repo at DeepSQLAI/deepsql is now Apache-2.0 and billed as "self-hosted and air-gapped." Separately, someone read install.sh and found the installer routed schemas and queries through DeepSQL's shared managed Azure OpenAI key; the founder confirmed it, said the bundling would be lifted, and promised BYOK for enterprise deployments. Both episodes point at the same lesson, which is the subject of the next section.
Why "self-hostable" is the load-bearing word
Think about what a DBA agent ingests to do its job: your full schema, your query log, samples of actual rows for BI answers, and — unless you configure otherwise — whatever PII sits in those rows. A SaaS DBA agent exfiltrates all four categories to someone else's infrastructure by design, then adds a fifth: the prompts your team types when production is on fire, which read like a guided tour of your system's weak points.
That is why the bundled-LLM-key episode mattered more than a launch-day rough edge. For the convenience of consistent agent performance, every schema and query flowed through the vendor's shared model resource — exactly the data flow a database agent's threat model should forbid by default. Self-hosting flips it: the agent, its prompts, and its query log stay on your network, and with BYOK even the model calls stay inside your own account boundary.
But self-hosting solves only the where, not the what. A local agent holding superuser credentials to your primary is still superuser — it can drop tables, read PII columns it was never meant to see, and run a cartesian join that melts your buffer cache at 3 AM. "Runs on my machines" is necessary and not sufficient. The sufficient part is the permission ladder.
The permission ladder: five rungs, both engines
Each rung below assumes the previous ones. The Postgres and MySQL columns give you copy-pasteable starting points; adjust schema and table names to your database.
| Rung | What the agent gets | Postgres | MySQL | Skip cost |
|---|---|---|---|---|
| 1. Own-nothing identity | A dedicated login that owns zero objects | CREATE ROLE dba_agent WITH LOGIN PASSWORD '…'; GRANT CONNECT ON DATABASE prod TO dba_agent; | CREATE USER 'dba_agent'@'%' IDENTIFIED BY '…'; | Shared or superuser credentials mean every agent bug is a DBA-privileged bug |
| 2. Least-privilege reads + stats | SELECT on exactly the tables it needs, plus stats views | GRANT USAGE ON SCHEMA public TO dba_agent; GRANT SELECT ON ALL TABLES IN SCHEMA public TO dba_agent; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO dba_agent; GRANT pg_monitor TO dba_agent; — then carve PII tables back out with column-list grants: REVOKE ALL ON users FROM dba_agent; GRANT SELECT (id, created_at, status) ON users TO dba_agent; | GRANT SELECT, SHOW VIEW ON prod.* TO 'dba_agent'@'%'; GRANT SELECT ON performance_schema.* TO 'dba_agent'@'%'; — and never SUPER, FILE, CREATE, ALTER, or DROP | pg_monitor covers pg_stat_statements, replication, and vacuum stats; without it the agent asks for wider access to do basic triage |
| 3. Session guardrails | Read-only transactions and a kill switch on runaway queries | ALTER ROLE dba_agent SET default_transaction_read_only = on; ALTER ROLE dba_agent SET statement_timeout = '30s'; | No per-role read-only setting exists — enforce it with the replica in rung 4 — but cap runaway reads via init_connect='SET SESSION max_execution_time=30000' (milliseconds, SELECT only) | One bad join plan without a timeout is a self-inflicted outage |
| 4. Replica-first routing | Read traffic physically cannot write | Connect the agent to a hot standby: the server rejects writes no matter what the session claims | Connect the agent to a read-only replica (read_only=1); FILE-less grants also block INTO OUTFILE exfiltration | A primary connection turns every guardrail bug below into a production-write bug |
| 5. Writes only as artifacts | Change proposals, never live DDL | Agent writes migration files; CI applies them. Short-lived creds (Vault dynamic secrets, IAM DB auth) for approved windows; pgaudit or log_statement='ddl' records everything | Same shape: migration files + CI, short-lived creds, audit plugin logging | An agent that can ALTER TABLE directly will eventually do it at the worst possible time |
Three notes on the table. First, pg_monitor is doing quiet heavy lifting in rung 2: slow-query triage, index recommendations, and vacuum and replication health all read from statistics views, and granting the stock monitoring role is far safer than improvising wider grants when the agent complains it can't see something. The ALTER DEFAULT PRIVILEGES line matters just as much — without it, every table created after the grant is invisible to the agent, and the resulting "it can't see my new table" ticket ends with someone over-granting to make the error stop. Second, MySQL's missing per-role read-only default is exactly why rung 4 is structural rather than advisory — on MySQL, the replica is the read-only enforcement. Third, note the PII carve-out uses column-list grants, not a column REVOKE on top of a table-wide grant: Postgres checks table-level or column-level privilege, so a table-wide SELECT still exposes every column no matter what you revoke at column level. Column lists keep the agent's BI surface away from PII without forking your schema into agent-safe views on day one; graduate to redaction views when the policy gets complicated.
Why app-layer guardrails aren't enough
Every rung above is enforced by the database server, and that placement is deliberate. The summer of 2026 supplied a clean demonstration of what happens when the enforcement lives in the agent's own SQL filter instead.
CVE-2026-85620, disclosed in September with a CVSS v4.0 score of 9.2, bypassed Postgres MCP Pro's "restricted mode" — read-only transactions plus an SQL allowlist — with a single syntactic trick. The validator checked function calls against its allowlist only when they parsed as FuncCall AST nodes, but a function in a FROM clause parses as a RangeFunction node, which passed unchecked. So SELECT pg_read_file('/etc/passwd') was blocked while SELECT * FROM pg_read_file('/etc/passwd') executed, escalating database access into host filesystem reads. One parsing edge case the allowlist author didn't consider, and the entire safety control evaporated.
The bypass class is bigger than one package. A read-only transaction wrapper alone doesn't survive multi-statement input — COMMIT; DROP TABLE users; sent as one query string ends the read-only transaction the wrapper was counting on, as one MCP-server teardown demonstrated. And human approval prompts, the usual backstop, catch far less than operators assume: research on AI coding agents puts successful human intervention at only 9 to 26 percent.
This is why the ladder's enforcement lives in GRANT statements, not agent configuration. A database role is enforced by the server on every statement regardless of which client, tool, or prompt-injected query string arrives holding the credentials — as TigerData's guide puts it, the restriction holds for tools you haven't configured yet or don't control directly. An agent holding one credential that can do everything isn't an agent; it's an unattended administrator with a chat interface. The ladder's job is to make sure no single credential the agent holds can do everything.
The line between copilot and incident generator
With the ladder in place, the rule is simple to state and to audit. Introspection autonomy is fine: let the agent monitor continuously, propose indexes, draft query rewrites, and answer BI questions — on a replica, inside a statement timeout, with PII columns revoked. Change autonomy is never direct: schema changes, index builds, and vacuum tuning ship as versioned migration files through the same review and CI path a human DBA's changes take, and any live write window uses short-lived credentials that expire when the window closes.
That split maps cleanly onto how DeepSQL itself is built — continuous monitoring and recommendations from the agent, execution on replicas, PII policy enforcement as a module — and onto the teams most likely to adopt it. If you run your database beside a git-push PaaS precisely because the platform refuses to manage one for you, the DBA agent is your night-shift hire: tireless at watching pg_stat_statements at 3 AM, but with no more authority than the narrowest role that lets it do the watching. Copilots propose; only reviewed artifacts dispose.
Running Postgres or MySQL next to your app servers because your PaaS won't manage one? That's the setup Bex.co is built for — push a git repo, get a running HTTPS service on machines you own, and keep the database beside it under your own credentials. Star the repo on GitHub or deploy your first app today.



