2026-10-01 · 6 min read · Rahul Chitturi
- sql
- postgresql
- timeouts
PostgreSQL can stop work for three different reasons that logs often flatten into the word timeout. statement_timeout limits how long one statement may run. lock_timeout limits how long that statement may wait to acquire a lock. idle_in_transaction_session_timeout ends a session that is sitting inside an open transaction with no new query.
The fix depends on which limit fired. Raising statement_timeout does not help a session that was terminated while idle, and raising lock_timeout does not help a query that was executing the whole time.
Match the message before you change a number
A statement timeout cancels the statement and leaves the session connected. The message is canceling statement due to statement timeout. A lock timeout also cancels the statement, with canceling statement due to lock timeout. An idle-in-transaction timeout terminates the connection and rolls the open transaction back. The message is terminating connection due to idle-in-transaction timeout.
Read the SQLSTATE your server version reports, because the idle-session codes became more specific in later releases. Keep the query text, the wait event, and the setting values from that same session.
- Record current_setting for each of the three timeouts.
- Note whether the source is a role, database, session, or config file.
- Check pg_stat_activity wait_event before the statement disappears.
- Do not compare a timeout copied from a different role.
See which clock is actually running
statement_timeout starts when the command arrives and includes time spent waiting on locks. If both statement_timeout and lock_timeout are set, the earlier one wins. A five-second lock_timeout therefore fails a blocked update before a thirty-second statement_timeout can.
idle_in_transaction_session_timeout does not measure query execution. It measures silence after BEGIN, or after a statement, while the transaction is still open. idle_session_timeout is the sibling for a session that is idle and not inside a transaction. Changing one does not configure the other.
Check the pooler before you edit postgresql.conf
SET LOCAL lasts for one transaction. A transaction-mode pooler returns the server connection at commit, so a later request can land on a connection that never saw that SET. A role or database setting still applies when the server connection is opened.
Use Flashman's SQL formatter to make the timeout statements readable, the timestamp converter to compare log lines with the limit, the JSON formatter for pg_stat_activity exports, and diff to compare the settings captured during the incident with the settings in the ticket.