SQLSTATE 25006 ERROR Class 25: Invalid Transaction State

read_only_sql_transaction cannot execute … in a read-only transaction — 25006

PostgreSQL error "cannot execute … in a read-only transaction" (SQLSTATE 25006): what it means, common causes, and how to fix it.

PG 12, 13, 14, 15, 16, 17, 18 Official docs
Last reviewed May 2025 Grounded in source

Diagnostic Queries

Symptoms

A write was attempted in a read-only context — a read-only transaction, a hot-standby replica, or a server with default_transaction_read_only on. PostgreSQL raises SQLSTATE 25006 (read_only_sql_transaction).

  • The message names the command (INSERT/UPDATE/DELETE/DDL).
  • Very common when an app accidentally writes to a read replica.
  • Also from SET TRANSACTION READ ONLY or a read-only default.

What the server log shows

ERROR:  cannot execute INSERT in a read-only transaction

Why PostgreSQL raises this — what the manual says

the SET TRANSACTION reference (Notes):

“When a transaction is read-only, the following SQL commands are disallowed:”

A read-only transaction (or a standby in recovery) forbids any statement that would change durable data. The write is rejected with 25006 before execution.

Common causes

  • Routing writes to a read replica/standby.
  • default_transaction_read_only = on on the server.
  • An explicit BEGIN … READ ONLY or SET TRANSACTION READ ONLY.

Relevant GUC parameters

Parameter Default Effect
default_transaction_read_only off Makes new transactions read-only by default.
transaction_read_only off Read-only mode for the current transaction.

How to fix it

  1. Send writes to the primary, not a replica (fix connection routing).
  2. Start a read/write transaction: BEGIN; SET TRANSACTION READ WRITE; if appropriate.
  3. Turn off default_transaction_read_only where writes are expected.

Related & next steps

Reference: PostgreSQL 18 — SET TRANSACTION.

Was this helpful?