# Production database access without sharing passwords

> Why a shared database password has no owner, what it costs you, and how to give developers production data access without handing out credentials.

- Published: 2026-10-13
- Tags: access-control, sql-guards, audit
- Source: https://queryproxy.com/blog/production-database-access-without-shared-passwords/
- Language: en-US
- Author: Muhammet Şafak

---
You give developers production data access without sharing a password by
putting a broker between them and the database: the credential lives in one
place, people submit statements instead of connecting, and a second person
approves before anything runs. The reason to bother is not tidiness. A shared
password is the one control that cannot answer "who did this?".

## What is wrong with a shared password?

Three things, and each one gets worse as the team grows.

- **It has no owner.** If two engineers know it, the database sees one user. An
  audit entry that says `app_rw` ran a `DELETE` tells you nothing about which
  person typed it. [What database access control is](/what-is-database-access-control/)
  puts it as a principle: every action should trace to a person.
- **It is a copy the moment it is used.** It gets pasted into a client, a shell
  history, a `.pgpass` file, a chat thread. The
  [bastion host comparison](/compare/bastion-host/) describes the same effect:
  the credential stays valid until someone rotates it, which in practice is when
  somebody leaves.
- **Rotation is all or nothing.** Changing it breaks every person and script
  that uses it at once, so it does not get changed.

## Do a bastion host or a vault fix this?

They fix a different problem. A bastion makes reaching the database mean
reaching a jump box first, which means a key and a nameable person. A vault
keeps the password out of a wiki. Both are real improvements and both end where
the session begins. After the connection is forwarded, the engineer holds a live
session and the credential, nobody reviews the statement, and the result comes
back whole.

[AWS IAM database authentication](/compare/aws-iam-database-authentication/)
goes further on identity: it replaces the password with a short-lived token per
person. It still does not read the statement or ask a second person. Authenticated
and authorized are different questions. Access platforms such as
[StrongDM](/compare/strongdm/) and
[just-in-time access and PAM tools](/compare/just-in-time-access-pam/) decide who
gets in and for how long, and [Hoop.dev](/compare/hoop-dev/) puts a guard in
front of the database; the comparison pages say where each fits.

## What does a broker change?

A broker takes the credential out of people's hands and puts a workflow where
the connection used to be. With QueryProxy:

1. A DBA registers the target database. Host, port, database, username and
   password are encrypted at rest with AES-256, and the password is not shown
   again after saving.
2. A DBA grants a connection to a developer. Ungranted connections are invisible
   in the editor.
3. The developer submits SQL. The statement is parsed against the
   [SQL guards](/docs/sql-guards/) first, so a `WHERE`-less `UPDATE` never
   reaches a reviewer.
4. A DBA approves or rejects. Self-approval is blocked, and an administrator
   override is flagged in the audit log.
5. The worker connects with the stored credential, runs the statement, and
   writes each step to the audit log.

The reference for each step is the
[approval workflow](/docs/approval-workflow/). The point is the shape of the
change: the developer holds an identity in the portal, not a secret for the
database.

## Where does this fall short?

- **It is one more component.** The portal now holds your database credentials,
  so its host, its application key and its HTTPS setup matter. The
  [production hardening guide](/docs/production-hardening/) lists what to do
  before exposing it.
- **It is slower for ad hoc work.** A pending request waits until someone
  decides; there is no auto-expiry. If your team debugs production all day, a
  queue is friction by design.
- **Database-side limits are not there yet.** Read-only execution and a
  statement timeout enforced on the database are planned for v0.3.0. Until then,
  give people who only read a connection with `SELECT`-only privileges.
- **Keep a break-glass path.** An incident at 3 a.m. should not depend on the
  queue.

## Who should not bother?

A team of three with one database and migrations run from CI has no shared
password problem worth a portal. The pain starts when several people need to
look at production by hand, and you can no longer say who ran what. The engine
pages show where this lands on your stack:
[PostgreSQL](/postgresql-access-control/) and
[MySQL and MariaDB](/mysql-mariadb-access-control/).
