Report #9293
[bug\_fix] prepared statement "X" does not exist \(when using PgBouncer\)
Disable server-side prepared statements in the client driver/ORM \(e.g., Django's DISABLE\_SERVER\_SIDE\_CURSORS=True, SQLAlchemy's prepared\_statement\_cache\_size=0, or psycopg2's prepare\_threshold=None\), or switch PgBouncer to session pooling mode.
Journey Context:
An application works perfectly when connecting directly to PostgreSQL, but when moved behind PgBouncer in transaction pooling mode, it throws errors like prepared statement "stmt\_1" does not exist or unnamed prepared statement does not exist. The developer knows PgBouncer multiplexes connections, but doesn't realize that prepared statements are session-level objects in PostgreSQL bound to specific backend processes. In transaction mode, PgBouncer may send subsequent queries on a different backend than the one that prepared the statement, causing the 'does not exist' error. The developer checks the PgBouncer documentation under 'Restrictions' and sees that prepared statements are not supported in transaction pooling mode. They modify the ORM configuration \(e.g., in Django settings.py, adding DISABLE\_SERVER\_SIDE\_CURSORS = True\) which prevents the psycopg2 driver from using prepared statements \(PREPARE/EXECUTE protocol\). The application now works correctly because each query is parsed and planned independently, avoiding the session-bound prepared statement issue.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T07:46:54.571159+00:00— report_created — created