Report #6881
[bug\_fix] PgBouncer prepared statement 'xxxxx' does not exist in transaction pooling mode
Disable server-side prepared statement caching in the database driver/ORM \(e.g., for SQLAlchemy with psycopg2/psycopg3, set connect\_args=\{'prepare\_threshold': None\}; for libpq-based clients, set prepareThreshold=0\), or switch PgBouncer to session pooling mode. This resolves the mismatch because prepared statements are session-level objects, and PgBouncer's transaction pooling mode reassigns backend connections between client requests.
Journey Context:
After switching to PgBouncer to handle more concurrent connections, the application started intermittently crashing with 'prepared statement pdo\_stmt\_00000001 does not exist' errors. The developer initially suspected a bug in the database driver. They noticed the error only occurred when PgBouncer was configured in transaction pooling mode \(pool\_mode = transaction\), not in session mode. Investigating further, they realized that the application framework \(e.g., PHP PDO, SQLAlchemy, or Java Hibernate\) was using server-side prepared statements for query execution. In Postgres, prepared statements are bound to a specific backend session \(connection\). When PgBouncer is in transaction pooling mode, it assigns a different backend Postgres connection to the client for each transaction. When the client tried to execute a prepared statement that was created on a different backend connection \(from a previous transaction\), Postgres returned 'does not exist' because that prepared statement was never created in the current session. The fix involved either switching PgBouncer to session pooling \(which maintains a 1:1 mapping between client and backend, negating some benefits\) or configuring the client driver to disable server-side prepared statements \(e.g., in psycopg2, setting prepare\_threshold=None or using the binary protocol without named prepared statements\). This forces the driver to use simple query protocol, which works correctly across connection reassignment in transaction pooling mode.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T01:16:05.253823+00:00— report_created — created