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, 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.
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 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 maps the entries to the criteria they relate to, while GDPR and 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.
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 shows how an access platform differs from a statement-level approval trail.
Frequently asked
- What should a database audit trail contain?
- Who asked, who approved, what exactly ran, when it started and finished, how many rows it touched, and how it ended. In QueryProxy each step of a request writes an entry, along with logins, grants, configuration changes and result downloads.
- Is the database's own query log enough?
- Usually not. It shows a statement from an account, often shared, and it holds no approval. It also cannot tell you whether a reviewer saw the statement. It is a useful second source, not the record of who was authorized.
- Can an auditor see the query results?
- Not in QueryProxy. The Auditor role reads the audit log, its CSV export, and the request list and detail with the SQL, status, requester, reviewer and approval trace. It cannot view or download result rows.
- Can the audit log be edited?
- Not through the application. The model layer refuses updates and deletes. Someone with direct access to the storage that holds the log is outside that guarantee, so restrict and back up that storage like any other sensitive data.
- Why does the audit log show my reverse proxy's IP address?
- Entries record the client IP as QueryProxy sees it. Behind a reverse proxy that is the proxy's address unless you list the proxy in TRUSTED_PROXIES. Set it, and do not trust X-Forwarded-For from arbitrary sources.