AI, CLI, and CI submit SQL. Policies decide. Trusted agents execute — and everything is audited.
Every database operation goes through the same flow. Pick a scenario.
Developer submits. DBA reviews with EXPLAIN context and approves. Developer resumes when ready.
$ dbward execute \ "UPDATE orders SET status = 'archived' WHERE created_at < '2024-01-01'" Request 7f3a requires approval. Approvers: dba-team Run: dbward request resume 7f3a $ dbward request resume 7f3a Waiting for agent to execute... Rows affected: 847203
$ dbward request list --pending-for-me 7f3a UPDATE orders ... @alice $ dbward request show 7f3a Request 7f3a Status: pending Detail: UPDATE orders SET status ... Risk: high (large_table, no_limit) SQL Review: 2 warnings Explain: Seq Scan on orders rows=847203 cost=0.00..28941 $ dbward request approve 7f3a \ --comment "Off-peak confirmed" Approved step 1/1
AI proposes SQL via MCP. Human approves in another terminal. AI receives result.
AI: Let me check which users haven't logged in since January. → tool: dbward_execute_query database: primary environment: production sql: "SELECT id, email, last_login FROM users WHERE last_login < '2026-01-01'" ⚠ Request a3c1 requires approval. — waiting for human approval — ✓ 1,204 rows returned (31ms) AI: Found 1,204 inactive users.
$ dbward request list --pending-for-me a3c1 SELECT id, email... @alice $ dbward request show a3c1 Request a3c1 Status: pending Detail: SELECT id, email, last_login FROM users WHERE last_login ... Risk: low SQL Review: passed Explain: Index Scan on idx_users_login rows=1204 cost=0.42..892 $ dbward request approve a3c1 \ --comment "LGTM" Approved step 1/1
Request triggers a Slack notification. Approve directly from the channel.
3 AM incident. Admin bypasses approval with --emergency. Fully audited, Slack alerted.
$ dbward execute \ "SELECT pg_terminate_backend(12345)" \ --emergency --reason "connection pool exhausted, app down" 🚨 Break-glass activated Skipping approval — admin emergency override ✓ Executed on agent-prod-01 (8ms) Audit: evt_d4e5...1209 (type: break_glass) # Slack webhook fires immediately: 🚨 BREAK-GLASS by @mike Reason: connection pool exhausted, app down SQL: SELECT pg_terminate_backend(12345)
Staging skips approval. Same audit trail, zero friction for safe queries.
# Staging: auto-approve low-risk queries [[auto_approve]] database = "*" environment = "staging" risk = "low" allow_read_only = true allow_safe_ddl = true # Development: auto-approve everything [[auto_approve]] database = "*" environment = "development" risk = "high" # Production: no [[auto_approve]] entry # → all requests require human approval
$ dbward -e staging execute \ "SELECT id, name, email FROM users WHERE active = true" id | name | email ----+----------+--------------------- 1 | Alice | alice@example.com 2 | Bob | bob@example.com 3 | Carol | carol@example.com … | | (2341 rows)
Migrations use the same approval workflow. File on the left, flow on the right.
-- migrate:up CREATE TABLE orders ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), status TEXT NOT NULL DEFAULT 'pending', total_cents INTEGER NOT NULL, created_at TIMESTAMPTZ DEFAULT now() ); -- migrate:down DROP TABLE orders;
$ dbward migrate status version | status ----------------------------+--------- 20260501_create_users | applied 20260502_add_email_index | applied 20260503_create_orders | pending (3 rows) $ dbward migrate up Request m1a2 requires approval. Approvers: dba-team Run: dbward request resume m1a2 # After approval... $ dbward request resume m1a2 Waiting for agent to execute... Applied migrations: ✓ 20260503_create_orders
Structural credential isolation. Even if the server is compromised, your database stays safe.
Submits requests.
Receives results.
Policy engine. Approval state.
Audit log. Token signing.
Executes approved SQL.
DB credentials here only.
Protected resource.
Agent-only access.
Developer machines never have DB credentials. Not even temporarily.
Agent polls the server. No inbound ports. Deploy in your private subnet.
Ed25519 signed. Includes SHA-256 of SQL + target. Can't be reused.
No matching workflow = rejected. Deny by default.
Not just approval gates. A complete execution control plane.
Multi-step approval with role and group-based approvers. Conditional auto-approve by risk level. Rate limiting per database × environment. All defined in TOML, hot-reloaded via SIGHUP.
Every statement goes through Classification → Review → Risk Scoring before execution. 10 configurable review rules (warn/block/off). Dangerous function detection (24 functions). Multi-statement rejection.
EXPLAIN runs automatically before approval. Approvers see rows estimate, cost, scan type, and table size. Schema snapshots collected by agent. No guesswork.
SHA-256 hash chain linking all events. 24 event types. SQL redaction (literals/full/none). Verify integrity with dbward audit --verify. Tamper-evident by design.
12 tools, 6 prompts, schema resources, elicitation support. Works with Cursor, Claude Code, Copilot, Kiro. AI proposes — cannot bypass approval or trigger break-glass.
Approval ≠ immediate execution. The requester calls resume when timing is right. Results relayed in-memory (10min TTL) or persisted to storage.
One-click approve/reject from Slack. Modal shows full SQL + EXPLAIN + risk. Messages update in-place as requests progress. Per-environment channels. Account linking.
Generic webhooks with HMAC-SHA256 signature. Notification policies route events per database × environment. Retry with exponential backoff. SQL redaction in payloads.
3 built-in roles + custom roles scoped to database × environment. Groups as approvers. Self-approval prevention. OIDC role mapping.
OIDC: TeamEmergency bypass with --emergency --reason. DDL repair with --allow-ddl. Admin-only. Immediate Slack alert. Prometheus metrics. Not available via MCP.
up / down / status / create / repair. dbmate-compatible format. Same approval workflow. Non-transactional mode for CONCURRENTLY. Configurable statement timeout.
3 self-contained binaries + embedded SQLite. No external control-plane DB. One-line install. Docker images. Hot-reload config via SIGHUP — zero downtime policy changes.
Cursor, Claude Code, Copilot propose SQL. dbward ensures humans approve before production. AI never gets credentials.
Replace shared DB passwords with policy-driven access. Tamper-evident audit for every production operation.
Production safety without heavyweight tooling. Zero external dependencies, 5-minute setup.
5 minutes. No external dependencies. Free for small teams.
Free: 3 databases / 20 users / full approval + audit. Team: $149/mo →