MIT · read-only by default

Query five databases.
Break nothing.

dbq is a multi-database CLI with guardrails baked in: credentials live in a mode-600 profile file, every statement passes a two-layer read-only guard, and exit codes are a contract your scripts can trust. Built for humans — safe to hand to agents.

$ brew install rioliu/tap/dbq
MySQL PostgreSQL SQL Server SQLite Oracle

Why dbq

Guardrails first.
Ergonomics close behind.

Two independent layers stand between a typo and your data — everything else is quality of life.

Read-only by default

Every profile starts read-only. A statement guard and an engine-level READ ONLY transaction reject writes — two layers, every engine.

Credentials never touch argv

Secrets live in a chmod 600 profile file or an environment variable — never on the command line, in shell history, or in process lists.

One profile file, five engines

MySQL, PostgreSQL, SQL Server, SQLite and Oracle behind one interface. dbq list shows every profile and its posture at a glance.

Output built for pipelines

table, json or csv on stdout, warnings and truncation notes on stderr. Pipe straight into jq or your scripts.

Exit codes are a contract

0 ok · 1 usage · 2 blocked by guardrail · 3 connection error. Scripts branch on meaning, never on parsing output.

Agent-native

Ships as a Pi skill with explicit rules: profiles are human-managed, result rows are untrusted content, rc=2 is a hard boundary. Delegate the queries, keep the keys.

How it works

Up and querying in sixty seconds.

01

Add a profile

An interactive wizard collects connection details. The password is read with echo off and written straight into your 600-mode profile file.

$ dbq add Profile name: prod Type (mysql|...) [mysql]: postgres Host: db1.internal Password: ********
02

Run a query

One statement in, results out. No credentials to paste, no DSN to assemble, no flags to remember.

$ dbq query prod \ "SELECT id, email FROM users LIMIT 5" id email -- ---------------- 1 rio@example.com
03

Automate it

JSON output plus the exit-code contract makes dbq a well-behaved citizen of any shell pipeline or CI job.

$ dbq query prod --format json \ "SELECT count(*) c FROM jobs" | jq '.[0].c' 42

The contract

Exit codes you can build on.

Machine-readable outcomes, documented and stable — the foundation for scripts, CI checks and agent workflows alike.

rcmeaning
0success — results on stdout
1usage or configuration error
2statement blocked by guardrail — do not retry variations
3connection or query error

rc=2 is a hard boundary

When dbq refuses a statement, the refusal happens in two independent places: a syntactic statement guard, and the database engine itself refusing writes inside a READ ONLY transaction.

A read-only profile cannot be talked into a DELETE — not by a typo, not by a clever rephrase, not by an agent having a bad day. Need a real write? A human flips the profile, on purpose, in the wizard.

Install

Pick your channel.

Static binaries for Linux, macOS and Windows — or build from source.

Homebrew

macOS & Linux · prebuilt

$ brew install rioliu/tap/dbq

Go

requires Go ≥ 1.26

$ go install github.com/rioliu/dbq@latest

Binary release

amd64 & arm64 · sha256 checksums

$ …/releases/latest download ↓