# What a production query audit trail should record

> What a production query audit trail should record, why database logs alone fall short, and what to check before you hand the trail to an auditor.

- Published: 2026-10-13
- Tags: audit, access-control, chatops
- Source: https://queryproxy.com/blog/production-query-audit-trail/
- Language: en-US
- Author: Muhammet Şafak

---
A production query audit trail should let you answer, for any statement that ran,
who asked for it, who agreed, what exactly ran, and what it did. If the record
only says that a connection happened, it cannot answer any of those, and that is
what most database logs give you.

## What do database logs miss?

A database sees an account and a statement. When a team shares one account, as
discussed in
[production database access without shared passwords](/blog/production-database-access-without-shared-passwords/),
the log names the account, not the person. It has no notion of an approval, so
it cannot show that a second person read the statement before it ran.

None of that makes the database log useless. Keep it as an independent source.
It is just not the record of who was authorized.

## What should each entry carry?

Think of the questions an auditor asks of a change to production data:

- **Who requested it**, as a named person, not an account.
- **Who approved it**, a different person, and through which channel: the web
  queue or a chat message.
- **What exactly ran**, the prepared SQL and not a paraphrase.
- **When it started and finished**, with the duration.
- **What it touched**, as an affected-row count for writes.
- **How it ended**, completed or failed.
- **What surrounds it**: logins, grants, configuration changes and result
  downloads, because access is also granted and used outside the query itself.

QueryProxy writes an entry for every step of a request: submission, decision
(with channel and override flag), execution start and finish with duration and
affected rows, and result downloads, plus logins, grants and configuration
changes. The reference is the
[approval workflow](/docs/approval-workflow/).

## Who should be able to read it?

Not everyone who can query. In QueryProxy the audit log is reserved to the
Auditor and the Admin; a DBA has no access to it. The Auditor role is read-only
and can export the trail as CSV, and it reads the team's request list and
detail: SQL, status, requester, reviewer and approval trace. It cannot view or
download result rows. That separation matters: the person checking the record
should not need to see the data to do it.

## Can the trail be trusted?

Two honest limits.

First, "immutable" here describes the application. The model layer refuses
updates and deletes, so no screen and no API lets anyone edit an entry. It says
nothing about someone with direct access to the storage under it. Treat that
storage as sensitive and back it up.

Second, the IP address is only as good as your proxy setup. Entries record the
client IP as QueryProxy sees it. Behind a reverse proxy that is the proxy's own
address unless you list it in `TRUSTED_PROXIES`; the
[production hardening guide](/docs/production-hardening/) explains why trusting
`X-Forwarded-For` from anyone also forges the address in the trail.

A trail is also a record, not a monitor. It does not raise an alert when
something odd happens, so decide who reads it and how often.

## What does it do for compliance?

It produces evidence. It does not make a control pass. The request, its exact
SQL, a named approver who is not the requester and the outcome are the artifact
auditors ask for, and the
[SOC 2 page](/soc-2-database-access-controls/) maps the entries to the criteria
they relate to, while
[GDPR and database access](/gdpr-database-access/) covers the data-protection
side. What stays with your organization, such as access reviews and incident
response, is listed on those pages.

## Where do chat approvals fit?

Approving from Slack or Teams is convenient, so the trail has to cover it too.
A decision taken in chat is recorded with its channel and follows the same rules
as the web: self-approval is blocked, and an administrator override is flagged
in the trail. How that works is covered in
[approving SQL queries in Slack and Teams](/blog/approve-sql-queries-in-slack-teams/).

## When is a simpler setup enough?

If one person runs production and every change goes through reviewed
migrations, your version control history is already your audit trail. The need
appears when many people look at production by hand and someone later asks who
approved a statement.

If you are weighing other tools, the [StrongDM comparison](/compare/strongdm/)
shows how an access platform differs from a statement-level approval trail.
