Report #93560
[bug\_fix] FATAL: terminating connection due to idle-in-transaction timeout
Set PostgreSQL parameter idle\_in\_transaction\_session\_timeout \(e.g., to 300000ms\) to automatically terminate sessions that remain idle in transaction, preventing indefinite lock holding and xmin horizon bloat; combine with application-level try-finally blocks to ensure transactions are committed or rolled back promptly.
Journey Context:
A microservices architecture experienced gradual database performance degradation over weeks. Monitoring revealed steadily increasing table bloat \(dead tuples not being vacuumed\) and growing xmin horizon. pg\_stat\_activity showed hundreds of connections in state "idle in transaction" for hours, many holding RowExclusiveLocks on tables. Investigation traced these to a Python service using SQLAlchemy: the ORM session.begin\(\) was called at request start, but if a specific exception handler triggered early, the function returned without explicit session.rollback\(\) or commit\(\). The connection returned to the pool with the transaction still open, holding locks and preventing vacuum from reclaiming dead tuples \(since xmin was frozen\). The immediate fix was configuring PostgreSQL's idle\_in\_transaction\_session\_timeout to 5 minutes \(300000ms\), causing Postgres to automatically kill these zombie connections, which the app then handled as disconnects. Long-term, the code was fixed to use try-finally blocks ensuring rollback on exceptions.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T15:37:40.127964+00:00— report_created — created