# 57P05 — idle_session_timeout

> Source-backed full entry for PostgreSQL SQLSTATE 57P05.
---

# 57P05

## At a glance {#at-a-glance}
`57P05` terminates a session after `idle_session_timeout` expires while the backend is truly idle between commands. The fixed code starts this timer only in the no-transaction branch; idle-in-transaction has a separate condition and timer.

<!-- BEGIN SQLSTATE FACTS: generated by scripts/generate.py; do not edit -->

| Field | Value |
| --- | --- |
| SQLSTATE | `57P05` |
| Condition | `idle_session_timeout` |
| Status | `active` |
| Known present by | `14.0` |
| Locked snapshots | `14.24, 15.19, 16.15, 17.11, 18.6, 19beta3` |
| Macros | `ERRCODE_IDLE_SESSION_TIMEOUT` |
| Aliases | `—` |

<!-- source facts: data/errcodes/57P05.json -->
<!-- END SQLSTATE FACTS -->

## Meaning {#meaning}
The fixed primary is `terminating connection due to idle-session timeout` at FATAL. In `PostgresMain`, the idle-session timer is enabled after the backend reports `STATE_IDLE` and only in the branch where `IsTransactionOrTransactionBlock()` is false. The timer is disabled as soon as a command is read. This makes `57P05` a session-lifecycle termination, distinct from statement timeout `57014`, lock timeout `55P03`, idle-in-transaction timeout `25P03`, and transaction timeout `25P04`.

## Messages {#messages}

- Primary: `terminating connection due to idle-session timeout`.
- Severity: FATAL; the timer interrupt terminates the connection rather than returning a recoverable statement ERROR.
- Boundary: a truly idle session between commands uses `57P05`; a session idle inside an open transaction uses the separate idle-in-transaction timer/condition.

## Diagnosis {#diagnosis}
Capture the primary, backend PID, `idle_session_timeout` value and source, last command, `pg_stat_activity` state, transaction status, and server log. Verify whether the session was `idle` or `idle in transaction` when the timer started. Elapsed client request time alone cannot distinguish this from statement or lock timeout, and the SQLSTATE should be interpreted with the connection's last ReadyForQuery state.

## Response {#response}
Close or recreate the expired connection and make long-lived work explicit rather than holding an unused session. Adjust `idle_session_timeout` only when policy permits and the workload needs it. Because FATAL closes the connection, there is no useful `ROLLBACK` command to send on that session; after reconnecting, verify durable effects before replaying a non-idempotent command. If the workload was idle in a transaction, diagnose `25P03`/`25P04` and transaction ownership separately.

## Versions {#versions}
The locked catalogue records this condition from 14.0; that boundary does not prove the exact implementation-introduction version. Fixed source coverage is PostgreSQL 18.6.

## Related {#related}
[`57P01`](../57p01/), [`25P03`](../25p03/), [`25P04`](../25p04/), [`57014`](../57014/), [`55P03`](../55p03/)

## Sources {#sources}
[`src/backend/tcop/postgres.c#L3504-3513`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/tcop/postgres.c#L3504)

[`src/backend/tcop/postgres.c#L4585-4650`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/tcop/postgres.c#L4585)

[`src/backend/tcop/postgres.c#L4704-4721`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/tcop/postgres.c#L4704)

The structured [evidence record](../data/evidence/57p05.json) records the message and idle-state boundary.
