Poisoned Postgres Connection Pools

Connection pooling bugs often look like database failures, but the real issue can be leaked session state moving between clients through PgBouncer.

Logged at IST: 2026-08-19 09:33 IST

What it is: PlanetScale's debugging note on poisoned Postgres connection pools, shared by Ben Dicken.

Gist: The failure mode is simple and nasty: PgBouncer transaction pooling reuses underlying database connections across clients. If one client leaves session state behind, the next client can inherit it.

The concrete example is read-only state. Application code used SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY for a read-only transaction, but that changed the session rather than only the transaction. Later requests reused that same underlying connection and started failing writes with Postgres error 25006 or ERROR: cannot execute INSERT in a read-only transaction.

The immediate antidote is to reset affected pooled connections with DISCARD ALL or kill/reset the pooler sessions. The durable fix is in application behavior: avoid session-level flags through PgBouncer, prefer transaction-scoped read-only settings with strict cleanup and timeouts, or route read traffic to replicas instead.

Newsletter angle: Useful database reliability story. Connection pools are not transparent plumbing; they preserve enough state that bugs in transaction boundaries, cleanup paths, and ORM behavior can escape one request and poison the next.

Embedded source