PostgreSQL idle session timeouts terminate inactive database connections to prevent lock accumulation and table bloat. Learn how to configure and troubleshoot idle_session_timeout and idle_in_transaction_session_timeout parameters.
PostgreSQL has two idle session timeout mechanisms. The idle_session_timeout parameter (PostgreSQL 14+) terminates sessions idle for too long, even outside transactions. The idle_in_transaction_session_timeout parameter (PostgreSQL 9.6+) specifically terminates sessions idle within an open transaction, preventing locks and dead tuples from accumulating. When a timeout is triggered, PostgreSQL automatically closes the connection and, in the case of idle_in_transaction, rolls back the pending transaction. This is a safety mechanism to protect database health, but can surprise applications that expect persistent connections.
Connect to your PostgreSQL database and query the current timeout settings:
SELECT name, setting FROM pg_settings WHERE name LIKE '%timeout%';Look for idle_session_timeout and idle_in_transaction_session_timeout values in milliseconds (0 means disabled). Also check statement_timeout and lock_timeout if relevant.
Check your application logs for the exact error message:
- "idle-session timeout" → idle_session_timeout is too low
- "idle-in-transaction timeout" → idle_in_transaction_session_timeout is too low
- No message but connection closes → check connection pooling or middleware timeout settings
This tells you which parameter to adjust.
Rather than changing postgresql.conf globally, set the timeout per role or database to minimize side effects.
For a specific user role:
ALTER ROLE your_application_user SET idle_in_transaction_session_timeout = '10min';For a specific database:
ALTER DATABASE your_database SET idle_in_transaction_session_timeout = '10min';For the current session only (testing):
SET idle_in_transaction_session_timeout = '10min';Common timeout values: '1min', '5min', '10min', '30min'. Start conservative and increase based on workload needs.
Adjust your application code to not hold connections idle:
- Commit transactions promptly after queries complete
- Close connections when not actively querying
- Use connection pooling (PgBouncer, pgpool) to recycle connections
- For batch jobs, commit after each batch of rows instead of one large transaction
- Use BEGIN/COMMIT blocks instead of leaving implicit transactions open
Example: Instead of holding a transaction for 30 minutes, process data in smaller chunks with commits between them.
If using connection pooling (PgBouncer, pgpool, etc.), ensure pool timeout settings align with PostgreSQL timeout settings:
# PgBouncer example
idle_in_transaction_session_timeout = 600000 # 10 minutesThe pool's timeout should be greater than PostgreSQL's timeout, otherwise the pool closes connections before PostgreSQL can enforce its timeout.
Reload the PostgreSQL configuration to apply changes:
SELECT pg_reload_conf();Or restart PostgreSQL for changes to postgresql.conf:
sudo systemctl restart postgresqlTest your application with long idle periods to confirm the new timeout allows your workload to complete without terminating connections unexpectedly.
PostgreSQL 17+ introduces transaction_timeout, which limits total transaction duration regardless of idle time—useful for preventing long-running transactions entirely. For applications using database-as-a-service (AWS RDS, Azure Database), timeout settings may be pre-configured and you may only be able to adjust per-role or per-database settings, not globally. Be cautious with idle_session_timeout on service account connections; it's safer to use idle_in_transaction_session_timeout with a reasonable timeout (e.g., 2-5 minutes) to allow detection of stalled transactions while not harming interactive sessions. Table bloat from long-idle transactions in production can be diagnosed with: SELECT schemaname, tablename, n_live_tup, n_dead_tup FROM pg_stat_user_tables WHERE n_dead_tup > 10000 ORDER BY n_dead_tup DESC;
ERROR: syntax error at end of input
Syntax error at end of input in PostgreSQL
Bind message supplies N parameters but prepared statement requires M
Bind message supplies N parameters but prepared statement requires M in PostgreSQL
Multidimensional arrays must have sub-arrays with matching dimensions
Multidimensional arrays must have sub-arrays with matching dimensions
ERROR: value too long for type character varying
Value too long for type character varying
insufficient columns in unique constraint for partition key
How to fix "insufficient columns in unique constraint for partition key" in PostgreSQL