Report #71300
[bug\_fix] PostgreSQL idle in transaction holding back vacuum and causing table bloat
The root cause is application code starting a transaction \(BEGIN\) then not issuing COMMIT/ROLLBACK promptly, often due to network latency, user think-time, or bugs. The transaction holds back the xmin horizon, preventing vacuum from removing dead tuples and causing table/index bloat. The fix is to set the PostgreSQL parameter idle\_in\_transaction\_session\_timeout \(e.g., to '10min'\) to automatically terminate connections stuck in this state, combined with application fixes to ensure transactions are short-lived and properly closed in try-finally blocks.
Journey Context:
The database storage is growing rapidly despite autovacuum running constantly. Checking pg\_stat\_user\_tables shows high dead\_tuple\_ratio and vacuum lagging behind. Investigating pg\_stat\_activity reveals several connections in 'idle in transaction' state for hours, with xmin values holding back the global vacuum horizon. Tracing these connections reveals a background job that opens a transaction, fetches a batch of records, processes them with external API calls \(taking minutes each\), then commits. The long-running transaction prevents vacuum from removing dead tuples, causing massive bloat. The DBA implements idle\_in\_transaction\_session\_timeout = '10min' as a safety net, while developers refactor the job to process in smaller, independent transactions, immediately resolving the bloat issue.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T02:15:31.914670+00:00— report_created — created