Set `pool_mode = transaction` in `pgbouncer.ini` for the database entry that should use transaction pooling.
For psycopg3 applications, pass `prepare_threshold=None` in the connection string or `connect()` call to disable the driver's automatic server-side prepared-statement cache.
For psycopg2 applications, psycopg2 has no `prepare_threshold` parameter. Avoid server-side prepares by using plain `cursor.execute()` calls (not `cursor.callproc()` with explicit prepare) and by not using the `pgprepare` extension. Use SQLAlchemy's `use_native_uuid=False` and avoid `text()` constructs that trigger implicit prepares.
Verify the setup by connecting through PgBouncer and running `SHOW POOLS;` in the PgBouncer admin console — `sv_used` should be small relative to the number of application connections.
Test that queries succeed after connection hand-off by running a transaction that spans multiple statements and confirming no `prepared statement does not exist` errors.
Known gotchas
`prepare_threshold=None` is a psycopg3-only feature; psycopg2 does not have this parameter and silently ignores unknown keyword arguments in some wrappers.
Transaction pooling is incompatible with any session-level state: `SET` commands, advisory locks, `LISTEN`, and temporary tables are all lost when the connection is returned to the pool.
If you cannot modify the application to avoid prepared statements, fall back to `pool_mode = session` for that database entry, accepting reduced multiplexing.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp