select open change scope Open full search

PG.CENTER connects PostgreSQL documentation, reference, and ecosystem knowledge. Maintained by Pigsty.

SQLSTATE / CLASS 25 · INVALID TRANSACTION STATE

idle_in_transaction_session_timeout

SQLSTATE
25P03
Condition name
idle_in_transaction_session_timeout
Class
Invalid Transaction State
Source macro
ERRCODE_IDLE_IN_TRANSACTION_SESSION_TIMEOUT
Evidence
Observed at runtime in the source evidence
Analysis & operational context

English SQLSTATE atlas: authored explanations and source/runtime evidence are separate from the manual definitions. View source ↗

<h1>25P03 — idle_in_transaction_session_timeout</h1>

At a glance

25P03 is a FATAL session-termination condition. It fires when a session is waiting for the next client query inside an open transaction longer than the effective idle_in_transaction_session_timeout. The selected case uses 300 ms as a harness trigger, not as a production recommendation.

Meaning

This timeout protects the server from sessions that keep an open transaction while waiting for the client; it can retain locks and delay cleanup. It applies while the session is idle in the transaction, including the idle in transaction and idle in transaction (aborted) states, not while an active statement is running. statement_timeout cancels a statement, while transaction_timeout covers the total transaction lifetime on versions that support it. The selected run covers the non-aborted INTRANS case only.

Diagnosis

Before the session disappears, capture its effective SHOW idle_in_transaction_session_timeout (or the matching pg_settings row) on that timed session itself. A control connection's SHOW or pg_settings describes the observer backend and cannot establish another session's effective SET value. From the control connection, inspect pg_stat_activity fields such as pid, usename, application_name, client_addr, state, xact_start, state_change, query_start, and query for state IN ('idle in transaction', 'idle in transaction (aborted)'). If the state is already aborted, preserve the earlier root error and 25P02 as separate diagnostics; the selected run is the non-aborted INTRANS path. These identify the pool or application path and how long it has been idle; permissions can limit what an observer sees. Correlate the FATAL record by backend PID, SQLSTATE, error_severity = FATAL, and exact message. The selected psycopg/libpq stack surfaced 25P03 in the driver diagnostic and CSV; PG18 also supplied JSON. The original connection is closed, so its transaction status cannot be repaired with ROLLBACK.

Response

Treat the session as gone: discard it from the pool and reconnect before retrying idempotent work. Prevent recurrence by committing or rolling back before returning a connection to the pool, and by fixing the application path that leaves a transaction open. Do not lower this timeout to suppress the error; a shorter value makes termination more likely. Choose an effective value above legitimate idle periods, or set it to 0 only when the deployment deliberately accepts the lock and cleanup risk. When the server closes this session, it rolls back the open incomplete transaction before exiting; the dead connection cannot accept a later ROLLBACK. A known uncommitted transaction on this terminated session cannot be recovered through that connection. If a separate network failure occurred after a COMMIT may have been sent, reconcile the business result from a fresh connection before retrying; that uncertainty is not implied by every 25P03 FATAL.

FATAL message

The server source emits terminating connection due to idle-in-transaction timeout at FATAL severity; the original connection is terminated.

Observed diagnostics

18.6 (Homebrew) / latest: FATAL SQLSTATE 25P03; primary terminating connection due to idle-in-transaction timeout; backend PID 26447; original connection closed True; collector CSV 25P03; collector JSON 25P03; fresh probe 1. 10.21 (Debian 10.21-1.pgdg90+1) / pg10: FATAL SQLSTATE 25P03; primary terminating connection due to idle-in-transaction timeout; backend PID 81; original connection closed True; collector CSV 25P03; collector JSON not applicable; fresh probe 1.

Representative case

The SQL excerpt below is not a paste-all script: run the setting, PID, and BEGIN on a test connection, then stop sending it queries while a separate observer or log collector waits for FATAL; after the old connection is terminated, open a fresh owner connection for the final probe. The runner reads these statements from the shared registry; complete assertions, collector correlation, environment, and cleanup are in case export.

-- set_timeout
SET idle_in_transaction_session_timeout = '300ms';
-- backend_pid
SELECT pg_backend_pid();
-- begin
BEGIN;
-- probe
SELECT 1;

The SQLSTATE, diagnostics, states, and repair assertions for this excerpt come from the shared registry (SHA-256 95fd079c8bca77c6e3ffc398e404a218e4f810e5fa36e30127cbc6470a6d6eb2); structured evidence.

Authored evidence IDs: identity, timeout-path, runtime. Selected runtime records: runtime.25P03-batch2c-latest-20260909.latest, runtime.25P03-batch2c-pg10-20260909.pg10.

Versions and limits

The selected 300 ms termination case passes on PostgreSQL 18.6 and 10.21. PG18 has CSV and JSON collector records; PG10 has CSV only under its configured logging target. Both fresh owner connections run SELECT 1 successfully. The timeout value is deployment-specific; the case does not prescribe it.

Sources

Source evidence

Evidence belongs to the frozen source and runtime versions listed here. It is not a runtime verification of the selected manual version.

25P03 is idle_in_transaction_session_timeout in Class 25.

Method: Read the fixed condition row and macro.

Limits: The code is emitted at session termination severity FATAL in the selected path.

src.errcodes.18.6

ProcessInterrupts emits FATAL 25P03 after the session has remained idle inside an open transaction longer than idle_in_transaction_session_timeout.

Method: Trace the timeout interrupt and the fixed configuration documentation.

Limits: The server terminates the connection; ROLLBACK cannot be sent through that dead session.

src.postgres.18.6 src.config.18.6 src.calls.REL_18_6

Both selected targets received FATAL 25P03 for the exact backend PID, and a fresh owner connection successfully ran SELECT 1 after termination.

Method: Match collector records by PID, SQLSTATE, and message, then probe a fresh connection.

Limits: The selected timeout is 300 ms in a runner-owned disposable target; production timeout policy is deployment-specific.

runtime runtime.25P03-batch2c-latest-20260909.latest runtime.25P03-batch2c-pg10-20260909.pg10

The fixed monitoring documentation defines pg_stat_activity as one row per server process with current activity, including xact_start and state_change; pg_settings is defined over pg_show_all_settings for the current backend. Capture timeout settings on the timed session itself, because SHOW or pg_settings on an observer connection cannot establish another backend's effective SET value.

Method: Read the fixed monitoring view documentation and system-view definition before writing the observer/session diagnostic split.

Limits: Visibility of pg_stat_activity fields depends on observer privileges; the selected runtime records establish PID/log correlation, not universal monitoring permissions.

doc.monitoring.18.6 src.system_views.18.6

The fixed monitoring view distinguishes idle in transaction from idle in transaction (aborted); the timeout documentation's open-transaction scope covers idle waiting, while the selected runtime demonstrates only the non-aborted INTRANS path.

Method: Read the fixed pg_stat_activity state definitions alongside the timeout GUC description and compare them with the selected runtime status.

Limits: No aborted-transaction timeout was run in this batch; preserve any earlier root error and 25P02 separately when diagnosing that state.

doc.monitoring.18.6 src.config.18.6

The fixed protocol documentation states that when the backend closes a connection it rolls back any open incomplete transaction before exiting; the driver cannot send a later ROLLBACK on that closed session.

Method: Read the fixed protocol session-termination rule and align the recovery prose with the FATAL path.

Limits: This establishes server-side rollback on forced connection close; it does not resolve a separate network failure after a client may have sent COMMIT.

doc.protocol.18.6

Message templates

FATAL · fatal

Primary

terminating connection due to idle-in-transaction timeout

This is a static FATAL message; the driver may expose or omit SQLSTATE depending on client stack.

Reproduction & repair cases

idle_in_transaction_timeout · PG 10, 18

Preconditions

  • A runner-owned disposable target is provisioned.

Trigger: Set idle_in_transaction_session_timeout, BEGIN, wait idle, and probe the terminated session.

Expected assertions

  • The original session is terminated by the timeout
  • The collector records FATAL 25P03 for the matching backend PID
  • A fresh connection can execute SELECT 1

Repair: Use the state-specific recovery documented on the page; do not reuse a terminated connection.

Cleanup: Drop the case schema with an owner connection.

Recorded runtime evidence

18.6 (Homebrew) · passed

Run: 25P03-batch2c-latest-20260909

{
  "primary": "terminating connection due to idle-in-transaction timeout",
  "severity": "FATAL",
  "sqlstate": "25P03",
  "backend_pid": 26447,
  "status_before_timeout": "INTRANS",
  "collector_csv_sqlstate": "25P03",
  "fresh_connection_probe": 1,
  "collector_json_sqlstate": "25P03",
  "fresh_connection_status": "IDLE",
  "original_connection_closed": true,
  "collector_csv_error_severity": "FATAL",
  "collector_json_error_severity": "FATAL",
  "recovery_requires_new_connection": true
}
10.21 (Debian 10.21-1.pgdg90+1) · passed

Run: 25P03-batch2c-pg10-20260909

{
  "primary": "terminating connection due to idle-in-transaction timeout",
  "severity": "FATAL",
  "sqlstate": "25P03",
  "backend_pid": 81,
  "status_before_timeout": "INTRANS",
  "collector_csv_sqlstate": "25P03",
  "fresh_connection_probe": 1,
  "collector_json_sqlstate": null,
  "fresh_connection_status": "IDLE",
  "original_connection_closed": true,
  "collector_csv_error_severity": "FATAL",
  "collector_json_error_severity": null,
  "recovery_requires_new_connection": true
}
Version history 1
  1. PG 9.5 → 9.6added

Definition snapshot: english-manuals:0c3f0a39f86ad1d597c595d6ba7… · English manual source