Report #91766
[bug\_fix] FATAL: terminating connection due to idle-in-transaction timeout
Connections in 'idle in transaction' state hold row locks, block vacuum, and can cause transaction ID wraparound. This state occurs when an application starts a transaction \(BEGIN\) but neither commits nor rolls back, often due to network stalls, exceptions without rollback, or ORM session leaks. The fix is setting \`idle\_in\_transaction\_session\_timeout\` \(PostgreSQL 9.6\+\) to a reasonable value \(e.g., 5 minutes\) in postgresql.conf, causing Postgres to automatically terminate violators. Additionally, fix application logic to ensure transactions are short-lived and use try-finally blocks \(or context managers\) to guarantee COMMIT or ROLLBACK.
Journey Context:
A Django application shows progressively slowing queries over days. Developers check \`pg\_stat\_activity\` and see 20 connections in 'idle in transaction' state, some hours old, holding row locks on the orders table. They check \`pg\_locks\` and see these idle transactions hold RowExclusiveLock, blocking \`VACUUM\` from removing dead tuples. The database size grows \(bloat\) and transaction ID age \(\`age\(datfrozenxid\)\`\) approaches the 2 billion limit, risking shutdown. They trace the code and find a background task that opens a transaction, calls an external API, then commits. When the API is slow, the transaction remains open. They initially try killing connections manually with \`pg\_terminate\_backend\`, but new ones appear due to the logic bug. The fix is setting \`idle\_in\_transaction\_session\_timeout = 300000\` \(5 minutes\) in postgresql.conf and reloading. Now Postgres automatically kills these connections with FATAL: terminating connection due to idle-in-transaction timeout, releasing locks. They also refactor the background task to do the API call before starting the transaction, or use short transactions. This works because it prevents human-error-induced long transactions, allowing autovacuum to reclaim dead tuples and preventing table bloat and transaction wraparound.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T12:37:17.986883+00:00— report_created — created