SQLSTATE 25006Severity mediumLab verified

Incident brief

Read-only SQL transaction

A write was attempted inside a transaction explicitly marked READ ONLY. PostgreSQL blocked the write instead of allowing it.

Reproduced on PostgreSQL 16.14Verified 2026-07-16 (Docker lab, PostgreSQL 16.14)Reviewed by Verified against PostgreSQL 16.14 in an isolated lab environment

In 10 seconds

What
Read-only SQL transaction
What triggers it
BEGIN READ ONLY.
The fix
Don't open the transaction as READ ONLY if it needs to write to ordinary tables.
Proof
Reproduced on PostgreSQL 16.14 → An INSERT into an ordinary table inside a READ ONLY transaction was rejected with SQLSTATE 25006. No row was added.

The fix

What to do right now

The immediate, application-level response to this error.

  • Don't open the transaction as READ ONLY if it needs to write to ordinary tables.
  • Writes to temporary tables are allowed even inside a READ ONLY transaction — see the premium test.
  • Don't assume SET SESSION CHARACTERISTICS can flip the current transaction to read/write mid-flight — see the counterexample.
Fix — SQL
BEGIN;
INSERT INTO audit.events VALUES (1);
COMMIT;

Related & next steps

Follow the thread

Everything this error touches — jump straight to the sibling error, term, runbook, or parameter.

Verification

PG 16.14
Last verified
2026-07-16 (Docker lab, PostgreSQL 16.14)
Reviewed by
Verified against PostgreSQL 16.14 in an isolated lab environment
Audit status
reviewed