Report #40209
[bug\_fix] idle in transaction state holding back xmin and vacuum
Set \`idle\_in\_transaction\_session\_timeout\` to automatically terminate connections idle in transaction for too long \(e.g., '10min'\), and ensure applications use proper try/finally blocks or context managers to always commit or rollback transactions even when exceptions occur.
Journey Context:
Your application gradually slows down over several days, with query performance degrading and disk usage growing despite deletes. You query \`pg\_stat\_activity\` and see multiple connections in \`idle in transaction\` state with \`xact\_start\` timestamps from hours ago. These transactions hold back the xmin horizon, preventing vacuum from removing dead tuples, leading to table bloat and eventually transaction ID wraparound issues. You investigate and find that your Python application opens a transaction, executes a query, but if an unhandled exception occurs in the business logic, the error bubbles up without executing the rollback, leaving the connection in an open transaction. You set \`idle\_in\_transaction\_session\_timeout = '10min'\` in postgresql.conf so Postgres automatically kills these zombie sessions, buying you time to fix the code. You then refactor all database access to use context managers \(\`with db.transaction\(\):\`\) that guarantee rollback on exception. After deploying, \`pg\_stat\_activity\` shows no long-running idle transactions, vacuum reclaims dead space, and performance stabilizes.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T21:57:48.974528+00:00— report_created — created