What it means
idle_in_transaction_session_timeout limits how long a session may sit inside an open transaction
without running anything. Your session ran BEGIN (or a statement with autocommit off), did some
work, and then waited longer than the limit before its next statement. The server ended the
whole connection, not only the transaction, and rolled back everything the transaction had done.
You usually see it on the next statement you send, since that’s when the client notices:
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.
The setting is off (0) by default, so something set it: the server’s configuration, the role, the
database, or a hosted provider. It exists because a transaction left open holds its locks and stops
VACUUM from cleaning up rows changed since it began.
Two sibling limits end the connection the same way:
transaction_timeout(PostgreSQL 17 and later) limits a whole transaction, busy or idle:terminating connection due to transaction timeout(code25P04).idle_session_timeout(PostgreSQL 14 and later) limits idle time outside a transaction:terminating connection due to idle-session timeout(code57P05).
Common causes
- Application code that begins a transaction and then waits: an HTTP call, a file upload, a
message queue, or a user’s input between
BEGINandCOMMIT. - A missing
COMMITorROLLBACKon an error path, so the connection goes back to the pool still inside a transaction. - Autocommit turned off in a client or driver (psycopg 2 and JDBC with
setAutoCommit(false), for example), so a plainSELECTopens a transaction that stays open. - An interactive session where someone ran
BEGIN, looked at some rows and went to lunch.
How to fix it
Find sessions that sit idle in a transaction
SELECT pid, usename, application_name, client_addr,
now() - xact_start AS in_transaction, now() - state_change AS idle_for,
left(query, 60) AS last_query
FROM pg_stat_activity
WHERE state = 'idle in transaction'
ORDER BY xact_start;
last_query is the last statement the session ran before going idle, which usually points at the
code path.
Keep transactions short
Do the slow work (network calls, waiting for users, reading files) before BEGIN or after COMMIT.
Make sure every code path ends the transaction: use your language’s with/try … finally or the
framework’s transaction block rather than calling BEGIN and COMMIT by hand.
Raise or remove the limit for one role or session
If a job really needs a long-open transaction (a migration, a large export), raise the limit for it, not for everyone:
SET idle_in_transaction_session_timeout = '10min'; -- this session
ALTER ROLE reporting SET idle_in_transaction_session_timeout = 0; -- a role
To see where the current value comes from:
SELECT setting, unit, source FROM pg_settings WHERE name = 'idle_in_transaction_session_timeout';
Let the application reconnect
The connection is gone, so the pool must discard it and open a new one. Most pools test connections before handing them out; turn that on, then retry the work.
Reproduce it
On PostgreSQL 18.6, in psql, pausing with \! sleep 3 between statements:
SET idle_in_transaction_session_timeout = '2s';
BEGIN;
UPDATE seo_err_pg.invoices SET total = total WHERE id = 1;
\! sleep 3
SELECT 1;
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.
error: connection to server was lost
With \set VERBOSITY verbose, psql shows the code:
FATAL: 25P03: terminating connection due to idle-in-transaction timeout. The siblings, in new
sessions with \set VERBOSITY verbose:
SET transaction_timeout = '1s';
BEGIN;
SELECT pg_sleep(2);
FATAL: 25P04: terminating connection due to transaction timeout
SET idle_session_timeout = '1s';
\! sleep 2
SELECT 1;
FATAL: 57P05: terminating connection due to idle-session timeout
Each was followed by the same server closed the connection unexpectedly lines.
In Inlet
Inlet’s Activity monitor lists the server’s sessions and the locks they hold, and can end a session (Pro), such as one left idle in a transaction that’s blocking others. Its query editor supports transactions with manual commit; commit or roll back before you leave one open, or the server’s limit will end the connection.