Catch dangerous SQL before your database has to.
PostgreSQL · Python · AsyncIO · Docker
Formerly SQL Safety Proxy
OhMyDB is a developer-facing database safety layer that sits between normal database clients and the database server.
It inspects SQL before execution, classifies risky operations, estimates affected rows where supported, applies policy decisions, and can block or require confirmation before dangerous statements reach the database.
OhMyDB is an additional safety layer. It is not a replacement for least privilege, backups, database permissions, transactions, or normal operational safeguards.
📖 I Don't Trust Myself With Production Databases, So I Built OhMyDB
A short write-up on the problem behind OhMyDB, how the proxy works, and why I built it.
Current validated scope:
- PostgreSQL
- MySQL/MariaDB-compatible server protocol
Validated client paths include:
- psycopg
- asyncpg
- mysql-connector-python
MariaDB Connector/Python on Windows is not currently used as a release gate because of a reproducible native runtime crash in the validation environment.
Current stable release:
v1.1.0
The project is now branded as OhMyDB. Releases through v1.0.0 were published under the original SQL Safety Proxy name.
Want to see the safety flow first?
👉 Run the reproducible PostgreSQL demo
Databases are unforgiving.
A missing WHERE, an unexpectedly broad mutation, or an ambiguous SQL operation can turn a routine command into a costly mistake.
OhMyDB adds a fail-closed safety layer between your database client and the backend. It inspects risky operations before execution and refuses to silently bypass policy when behavior is malformed, ambiguous, or unsupported.
For a reproducible PostgreSQL walkthrough, see docs/DEMO.md.
Imagine an accidental mutation:
UPDATE customers
SET status = 'inactive';
Instead of blindly forwarding a potentially high-impact operation, OhMyDB evaluates it against its safety policy before it reaches the backend.
Typical flow:
Database Client
|
v
OhMyDB
|
+--> Inspect SQL
|
+--> Classify risk
|
+--> Estimate impact
|
+--> Apply policy
|
+--> Allow / Confirm / Block
|
v
Database
Run the proxy:
ohmydb --help
The legacy command remains available for compatibility:
sql-safety-proxy --help
If you are validating OhMyDB locally, start with the reproducible PostgreSQL walkthrough:
It covers the expected proxy flow, a safe query, a risky mutation, and verification that blocked operations leave the database unchanged.
- SQL classification
- policy actions: ALLOW, CONFIRM, BLOCK
- row-impact estimation for supported mutations
- no-WHERE mutation protection
- multi-statement safety handling
- fail-safe protocol-gap behavior
- audit logging
- secret sanitization and redaction
- PostgreSQL Simple Query support
- PostgreSQL extended protocol support
- PostgreSQL prepared statement and portal tracking
- PostgreSQL transaction-state tracking
- MySQL/MariaDB authentication relay
- MySQL/MariaDB session database tracking
- MySQL/MariaDB prepared-statement inspection
- MySQL/MariaDB transaction-state tracking
- Docker deployment
- CLI configuration
For development:
git clone https://github.com/omardoesdata/ohmydb-proxy
cd ohmydb-proxy
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"For package installation, install the released wheel or package artifact for the desired version.
Show help:
ohmydb --helpShow version:
ohmydb --versionAvailable CLI overrides:
--adapter {postgres,mysql,mariadb}--port--db-host--db-port--db-name
CLI values override their corresponding environment variables.
Example development configuration:
$env:DATABASE_ADAPTER = "postgres"
$env:DB_HOST = "127.0.0.1"
$env:DB_PORT = "5432"
$env:DB_NAME = "testdb"
$env:PROXY_PORT = "5433"
$env:ESTIMATOR_USER = "proxy_estimator"
$env:ESTIMATOR_PASSWORD = "replace-me"Start the proxy:
python -m sql_safety_proxyThen point the PostgreSQL client to:
127.0.0.1:5433
The real PostgreSQL server remains on its normal backend address, for example 127.0.0.1:5432.
Example development configuration:
$env:DATABASE_ADAPTER = "mysql"
$env:DB_HOST = "127.0.0.1"
$env:DB_PORT = "3306"
$env:DB_NAME = "testdb"
$env:PROXY_PORT = "3307"
$env:ESTIMATOR_USER = "proxy_estimator"
$env:ESTIMATOR_PASSWORD = "replace-me"Start the proxy:
python -m sql_safety_proxyThen point the MySQL/MariaDB client to:
127.0.0.1:3307
TLS termination is not currently supported on this proxy path, so compatible clients may need TLS disabled when connecting through the proxy.
Example safe query:
SELECT * FROM users WHERE id = 1;Example dangerous mutation:
UPDATE users SET active = 0;With the default no-WHERE safety policy, the second statement is expected to be blocked or otherwise handled according to policy before it reaches the database.
Important policy environment variables include:
POLICY_AUTO_ALLOW_MAX_ROWSPOLICY_BLOCK_AT_ROWSPOLICY_NO_WHERE_ACTIONPOLICY_STRUCTURAL_ACTIONPOLICY_UNKNOWN_ACTIONPOLICY_ESTIMATION_FAILURE_ACTIONPOLICY_MULTI_STATEMENT_ACTION
Typical actions are ALLOW, CONFIRM, or BLOCK where supported by the policy setting.
Supported modes include:
strictbalancedpermissive
The default mode is balanced.
Fail-safe behavior is intended to prevent unsupported or ambiguous protocol conditions from being silently treated as safe.
Audit logging can be enabled through environment configuration.
Important variables include:
AUDIT_ENABLEDAUDIT_LOG_PATH
Audit and runtime output are designed to avoid exposing credentials and bound prepared-statement values.
PostgreSQL extended-query state is tracked across Parse, Bind, Execute, Close, and Sync flows.
The MySQL/MariaDB path supports validated prepared-statement lifecycle inspection, including statement preparation, execution, reset, close, and supported binary parameter forms.
Unsupported or ambiguous prepared parameter types intentionally fail closed where safe inspection cannot be guaranteed.
Transaction state is tracked for supported PostgreSQL and MySQL/MariaDB runtime paths.
Blocked operations preserve protocol recovery behavior so client and backend state remain synchronized.
Build the image:
docker build -t ohmydb:1.1.0 .Check the image:
docker run --rm ohmydb:1.1.0 --version
docker run --rm ohmydb:1.1.0 --helpThe image runs as a non-root user and contains the proxy only. It does not bundle PostgreSQL, MySQL, or MariaDB servers.
See docker-compose.example.yml for example PostgreSQL and MySQL/MariaDB proxy services.
Public driver examples are available in examples/:
postgres_psycopg.pypostgres_asyncpg.pymysql_connector.py
The examples use environment-based credentials and should only be run against disposable development databases.
See:
docs/ARCHITECTURE.mddocs/THREAT_MODEL.mddocs/estimator-account.md
- TLS termination is not currently a fully validated supported capability.
- MySQL/MariaDB proxy clients may need TLS disabled.
- some prepared-statement parameter categories intentionally fail closed
- SQL classification cannot guarantee complete understanding of every possible dialect construct
- MariaDB Connector/Python on Windows is not a release gate
See SECURITY.md before using the proxy in security-sensitive environments.
Use least-privilege database accounts, a dedicated read-only estimator account, backups, change controls, and normal database security practices alongside the proxy.
Core validation includes:
python -m pytest -q
python -m compileall -q sql_safety_proxy
python -m pip check
git diff --check
python -m build
python -m twine check dist\*Pre-release validation also includes real PostgreSQL and MySQL/MariaDB runtime testing with real clients and representative safe and dangerous queries.
Unit tests alone are not considered sufficient for release validation.
The current v0.8 phase focuses on productization, documentation, examples, packaging, Docker, and user-facing quality.
The next planned milestone is a release-candidate phase focused on final compatibility, security, performance, and release hardening before v1.0.
Compatibility: the legacy
sql-safety-proxyCLI remains available during the OhMyDB transition.