The execution boundary for production databases.

AI, CLI, and CI submit SQL. Policies decide. Trusted agents execute — and everything is audited.

Open-core (Apache-2.0) PostgreSQL + MySQL Zero external deps Self-hosted

See it in action.

Every database operation goes through the same flow. Pick a scenario.

Developer submits. DBA reviews with EXPLAIN context and approves. Developer resumes when ready.

alice — requester
$ 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
sarah — approver (dba-team)
$ 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.

cursor — AI agent (MCP)
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.
mike — human approver
$ 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.

Slack Approval

3 AM incident. Admin bypasses approval with --emergency. Fully audited, Slack alerted.

terminal — admin (on-call)
$ 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.

dbward-server.toml
# 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
terminal — staging
$ 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.

20260503_create_orders.sql
-- 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;
terminal
$ 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

No single component has both
approval authority and DB access.

Structural credential isolation. Even if the server is compromised, your database stays safe.

CLI / AI / CI

Submits requests.
Receives results.

✓ Submit SQL
✓ View results
✗ No DB credentials
✗ Cannot bypass approval

Server

Policy engine. Approval state.
Audit log. Token signing.

✓ Evaluate policy
✓ Sign Ed25519 tokens
✗ No DB connection
✗ No credentials stored

Agent

Executes approved SQL.
DB credentials here only.

✓ Connect to DB
✓ Verify tokens
✗ Cannot approve
✗ Cannot modify SQL

Database

Protected resource.
Agent-only access.

✓ PostgreSQL
✓ MySQL
✗ No direct client access
✗ No server access
── CREDENTIAL BOUNDARY ── credentials exist only on the agent side ──

Request lifecycle

1Client submits SQL
2Server evaluates policy
3Human approves
4Client resumes
5Agent polls & executes
6Result relayed
Zero-trust client

Developer machines never have DB credentials. Not even temporarily.

Outbound-only agent

Agent polls the server. No inbound ports. Deploy in your private subnet.

Content-bound tokens

Ed25519 signed. Includes SHA-256 of SQL + target. Can't be reused.

Fail-closed

No matching workflow = rejected. Deny by default.

Everything you need to control production access.

Not just approval gates. A complete execution control plane.

🔐 Approval Workflows

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.

🛡️ SQL Safety (3 Layers)

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 & Impact Preview

EXPLAIN runs automatically before approval. Approvers see rows estimate, cost, scan type, and table size. Schema snapshots collected by agent. No guesswork.

📋 Audit Log

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.

🤖 MCP Server

12 tools, 6 prompts, schema resources, elicitation support. Works with Cursor, Claude Code, Copilot, Kiro. AI proposes — cannot bypass approval or trigger break-glass.

⏱️ On-Demand Execution

Approval ≠ immediate execution. The requester calls resume when timing is right. Results relayed in-memory (10min TTL) or persisted to storage.

💬 Slack Approval

One-click approve/reject from Slack. Modal shows full SQL + EXPLAIN + risk. Messages update in-place as requests progress. Per-environment channels. Account linking.

🔔 Webhooks & Notifications

Generic webhooks with HMAC-SHA256 signature. Notification policies route events per database × environment. Retry with exponential backoff. SQL redaction in payloads.

👥 RBAC & Custom Roles

3 built-in roles + custom roles scoped to database × environment. Groups as approvers. Self-approval prevention. OIDC role mapping.

OIDC: Team

🚨 Break-glass

Emergency bypass with --emergency --reason. DDL repair with --allow-ddl. Admin-only. Immediate Slack alert. Prometheus metrics. Not available via MCP.

🔄 Migrations

up / down / status / create / repair. dbmate-compatible format. Same approval workflow. Non-transactional mode for CONCURRENTLY. Configurable statement timeout.

Standalone & Zero Deps

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.

Who uses dbward.

Teams using AI agents

Cursor, Claude Code, Copilot propose SQL. dbward ensures humans approve before production. AI never gets credentials.

Platform / SRE

Replace shared DB passwords with policy-driven access. Tamper-evident audit for every production operation.

Teams without a dedicated DBA

Production safety without heavyweight tooling. Zero external dependencies, 5-minute setup.

Start protecting your production database.

5 minutes. No external dependencies. Free for small teams.

Free: 3 databases / 20 users / full approval + audit. Team: $149/mo →