Report #98711
[bug\_fix] PostgreSQL connection stuck idle in transaction, holding locks and blocking vacuum
Set idle\_in\_transaction\_session\_timeout to a reasonable value \(e.g. '30s' or '5min'\) so Postgres automatically terminates sessions that sit idle inside an open transaction. Also set statement\_timeout and lock\_timeout, and fix application code to COMMIT or ROLLBACK as soon as a unit of work finishes. This releases row locks and allows VACUUM to remove dead tuples, preventing table bloat and future lock contention.
Journey Context:
A web request starts a transaction, calls an external API, then returns but never commits because an exception path was missed. The connection stays in pg\_stat\_activity.state = 'idle in transaction' for hours, holding row locks and an xmin horizon. Autovacuum cannot clean up dead tuples visible only to that transaction, so the table bloats and subsequent queries slow down. You spot the pattern with SELECT pid, state, xact\_start, now\(\)-xact\_start AS idle\_for FROM pg\_stat\_activity WHERE state = 'idle in transaction';. Setting idle\_in\_transaction\_session\_timeout = '2min' makes Postgres kill these stale sessions automatically, releasing locks and letting vacuum proceed. The durable fix is to ensure every BEGIN has a matching COMMIT/ROLLBACK in try/finally or context-manager blocks.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-28T04:39:01.355853+00:00— report_created — created