# Introduction

> What QueryProxy is, the problem it solves, and how a query travels from a developer's editor to a masked, audited result.

- Documentation: Getting started
- Updated: 2026-10-10
- Source: https://queryproxy.com/docs/
- Language: en-US
- Author: Muhammet Şafak

---
QueryProxy is a **self-hosted database access control and query approval portal**.
It sits between your team and your databases so that developers can work with
production data without ever holding production credentials.

Instead of sharing passwords or opening ad-hoc tunnels, your team follows one flow:

1. **Submit** — a developer writes SQL in a guarded editor, against a connection
   a DBA granted them. Credentials stay in the encrypted vault.
2. **Guard** — the SQL is parsed and inspected before anything runs:
   `UPDATE`/`DELETE` without a `WHERE` is rejected, `SELECT` without a `LIMIT`
   gets one injected, and the statements that hand out server-level code
   execution or file access are blocked outright.
3. **Approve** — a DBA approves or rejects the request from the web queue or
   straight from Slack / Teams. Nobody can approve their own request.
4. **Execute** — a queue worker runs the query asynchronously, streams the
   result row-by-row, masks PII before it touches disk, and records every step
   in an immutable audit log.

## How it works

The same flow as a diagram. Every arrow is an audited step; the queue and the
worker are what run approved queries, so the worker is not optional.

```text
Developer ──▶ Query Studio ──▶ SQL guards (AST) ──▶ pending request
                                                        │
                       Slack / Teams ◀── notification ──┤
                            │                           │
                            ▼                           ▼
                     Approve / Reject ──────▶ queue ──▶ worker
                     (HMAC-verified)                    │ cursor streaming
                                                        ▼
                                        masked NDJSON result on storage disk
                                                        │
                              viewer / CSV download ◀───┘   (all steps audited)
```

## What you get

- **Teams & roles** — Admin, DBA, Developer and Auditor roles; connections,
  requests and audit trails are isolated per team.
- **Connection vault** — [PostgreSQL](/postgresql-access-control/),
  [MySQL and MariaDB](/mysql-mariadb-access-control/),
  [SQL Server](/sql-server-access-control/) and SQLite targets with
  AES-256-encrypted credentials.
- **SQL guards** — enforced by parsing, not pattern-matching. The idea behind
  them is explained in [database access control](/what-is-database-access-control/);
  [how it compares](/compare/) to other tools is covered separately.
- **ChatOps approvals** — interactive Slack buttons and a Teams action endpoint,
  both verified with timestamped, replay-protected HMAC-SHA256 signatures and a
  single-use action token per request; the signing secret can only be set by a
  system administrator.
- **Dynamic data masking** — column-pattern and content-regex rules applied
  while results are written.
- **Two-factor authentication** — optional TOTP with recovery codes, an
  instance-wide requirement you can enforce per role, and single-use codes.
- **Immutable audit log** — who asked, who approved, what ran, what it touched.

## Architecture at a glance

QueryProxy is a single Laravel application plus a queue worker and a scheduler —
all three run inside one container, started by a single `docker run`. By default it needs **no external
services**: the application database is SQLite and the queue is database-backed.
When you outgrow the defaults, MySQL/PostgreSQL and Redis are configuration
changes, not migrations.

## License

QueryProxy is open source under the
[AGPL-3.0](https://github.com/QueryProxy/QueryProxy/blob/main/LICENSE) license.
If you run a modified copy as a network service, you must publish your
modifications under the same license.

Ready to try it? Continue with the [Quick start](/docs/quickstart/).
