Incident brief
Idle in transaction session timeout
A session left an open transaction sitting idle (no query in flight) for longer than idle_in_transaction_session_timeout. PostgreSQL terminated the connection instead of letting it hold locks and a snapshot indefinitely.
What lands in your log
FATAL: terminating connection due to idle-in-transaction timeout
In 10 seconds
- What triggers it
- SET idle_in_transaction_session_timeout to a short value.
- Fix
- Don't leave a BEGIN open while waiting on something outside the database (user input, an external API call). Commit or roll back first, then reopen a transaction when you're ready to continue.
- Proof
- Reproduced on PostgreSQL 16.14 → A transaction left genuinely idle (no query sent, only a client-side pause) past the configured timeout was terminated by the server with SQLSTATE 25P03.
Fix
What to do right now
Application-level steps for this error.
- Don't leave a BEGIN open while waiting on something outside the database (user input, an external API call). Commit or roll back first, then reopen a transaction when you're ready to continue.
- Set idle_in_transaction_session_timeout as a safety net so a forgotten open transaction can't hold locks and an old snapshot forever.
-- application pattern: don't hold BEGIN open across an external wait
COMMIT; -- release the transaction before waiting on something external
-- ... do the external work here, outside any transaction ...
BEGIN; -- reopen only when ready to continueFor this error
See this error live on the server
Run these against the affected instance to confirm the diagnosis before you act.
Find sessions left idle inside a transaction and compare their age with the configured timeout. This is primarily an application transaction-lifecycle bug.
Idle transactions at risk of termination
Show age, backend_xmin, and last statement for every idle-in-transaction backend.
SELECT pid, usename, application_name,
now() - xact_start AS transaction_age,
backend_xid, backend_xmin, left(query, 120) AS last_query
FROM pg_stat_activity
WHERE state = 'idle in transaction'
ORDER BY xact_start;Effective idle-in-transaction timeout
Confirm the session/database/role-derived value before changing it.
SHOW idle_in_transaction_session_timeout;Why it happens
What PostgreSQL is telling you
The mechanism behind the error, grounded in the official manual, not paraphrased.
PostgreSQL 16 Documentation, Client Connection Defaults (20.11)
Terminate any session with an open transaction that has been idle for longer than the specified duration in milliseconds.Read the full section on postgresql.org →
The idle transaction
The transaction opened and ran one statement normally, the clock only starts once the session goes idle with no query in flight.What the next statement sees
By the time the next statement was sent, the session had been idle-in-transaction past the 1-second limit, so PostgreSQL had already terminated the connection.Reproduce & verify
A real, single-session PostgreSQL reproduction
A literal transcript of SQL run against a live PostgreSQL instance in an isolated lab. The commands below are exactly what was executed.
- 1SET idle_in_transaction_session_timeout to a short value.
- 2BEGIN a transaction, run one statement, then go idle (send nothing) past the timeout.
- 3The server terminates the session once the idle timeout fires. The client usually discovers it on the next command (FATAL / connection lost, SQLSTATE 25P03).
One client: lower the timeout, open a transaction, run one statement, then pause client-side (sending nothing) past the timeout.
SET idle_in_transaction_session_timeout = '1s';BEGIN;
SELECT 1;
-- client goes idle here for 3s, sending nothing to the serverSELECT 2; -- sent after the idle pauseWhat PostgreSQL actually returned
SETBEGIN
?column?
----------
1
(1 row)FATAL: terminating connection due to idle-in-transaction timeout
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
connection to server was lostThe deeper lab audit for this error
- Fix that misunderstands what counts as idle: exact SQL, output, and verdict
- A measured idle_in_transaction_session_timeout before/after
- A manual-grounded production interpretation of the lab result
Card required. Cancel before day 7 and you are not charged.
Runbook to fix this
Runbooks for this incident
Full step-by-step fixes for the condition behind this error: the diagnosis, the exact SQL, and output captured in the lab.
- Survive a connection storm when there is no poolerConnections pile up, the app times out, and CPU is high while throughput sits flat.Free
- Set sane statement, lock, and idle timeoutsEvery timeout ships as 0, so one runaway statement turns into an outage.Pro
- Stop idle-in-transaction sessions from holding locksA session sits idle in transaction, holding its locks and pinning vacuum.Pro
Connected
Everything this error touches
Every page this SQLSTATE connects to: the concept that explains it, the runbooks that fix it, the parameters you tune to prevent it, and the sibling errors it travels with. All real cross-references. Jump straight in, or open the full interactive map.
Understand the concept
Fix it — runbooks
Tune to prevent it
Related errors
Verification
- Last verified
- 2026-07-16 (Docker lab, PostgreSQL 16.14)
- Verification scope
- Verified against PostgreSQL 16.14 in an isolated lab environment
- Audit status
- reviewed
Went further?
Pro unlocks the second lab proof
Free page stops the bleeding. Pro adds the operational test, SQLSTATE audit, and deeper evidence, same error, more certainty.