Updated 2 November 2026
Using PgBouncer Safely with Authentication Sessions
Database connections and application sessions
PgBouncer pools database connections. Your application still verifies each user's session. Transaction pooling can support authentication queries, including supported prepared statements, when those queries do not depend on database connection state surviving between transactions. Choose the pooling mode from the features your database driver and queries use.
Database client authentication and application authentication are separate checks. PgBouncer authenticates the backend connecting to the database. Own Auth verifies the application user and their session. A database connection reused for another request does not change who owns a saved application session or which records that person may access.
Choose a pooling mode
Session pooling assigns a database connection to a client until that client disconnects. It supports database features that need connection state to survive between transactions. The client here is the database driver connection, not the person signed into the application. An application session can outlive many individual database connections.
Transaction pooling returns the database connection to the pool when a transaction finishes. Another transaction from the same client can use a different connection. Use this mode when each transaction contains the work and context it needs. Do not rely on session settings, session advisory locks, or temporary tables whose contents must remain available across transactions.
Statement pooling releases the connection after each statement and disallows transactions containing multiple statements. An authentication operation that must read and update records together in one transaction cannot use that mode.
Keep authentication operations together
Reading a session, inserting a verification token, updating a credential, and deleting expired records do not inherently require a dedicated database connection. They can work with transaction pooling when the driver and queries use supported features. If one operation contains several related statements, keep them in the same database transaction on the same checked out client.
Distinguish application session data stored in tables from database session state stored on a connection. The user ID, session expiry, and revocation status remain saved records. A setting made on a connection is different: a later transaction may use another connection where that setting is absent or has another value.
Prepared statements and transaction pooling
PgBouncer 1.21 and later supports protocol prepared statements in transaction pooling when max_prepared_statements is greater than zero. These are prepared statements created through the database driver's protocol. PgBouncer tracks them and prepares them on the database connection assigned to the transaction when needed.
SQL commands such as PREPARE have different limitations and are not covered by that protocol tracking. Check how your driver prepares queries, the installed PgBouncer version, and the configured value of max_prepared_statements. Prepared statements alone are not a reason to rule out transaction pooling. Use session pooling when the application requires features that remain tied to one database connection.
Connection cleanup and tenant access
In session pooling, server_reset_query normally runs when a client releases its database connection. Its default value is DISCARD ALL. This cleans connection state before that connection is assigned to another client.
In transaction pooling, this reset query is normally skipped. Setting server_reset_query alone does not make it run after every transaction. The separate server_reset_query_always option can force cleanup, but it does not make database state survive between transactions. It is not a substitute for selecting a compatible pooling mode.
Connection cleanup does not replace application authorization. Every request must still establish the application user and check access to the requested tenant and records. Do not treat a pooled connection as proof of which user is making the request.
Rate limit counters with pooled connections
Rate limit counters should identify the person, account, recipient, or request property being limited. The database connection used to update a counter is not the application user's identity. Sharing that connection across requests does not inherently merge counters belonging to different people.
Counters stored in database tables can work with connection pooling. Update them atomically so simultaneous requests cannot lose increments or each pass a limit that only one should pass. Avoid keeping enforcement state only in connection settings that may disappear when a transaction ends. When using Own Auth, retain its authentication rate limit checks rather than recreating them around the pooler.
Check the deployed configuration
Confirm the actual PgBouncer version, pooling mode, prepared statement setting, and driver behavior used by the application. Review each authentication operation for work that spans several statements and for connection state it expects to keep. Choose transaction pooling for compatible operations and session pooling for features that require a persistent connection. Keep user session verification and tenant access checks in place in either mode.
Frequently Asked Questions
What is the difference between session, transaction, and statement pooling in PgBouncer?
Session pooling holds a database connection until the client disconnects. Transaction pooling releases it after each transaction. Statement pooling releases it after each statement and disallows transactions containing multiple statements. Choose the mode from the features your queries use; an application user session does not require its own permanent database connection.
Can I use transaction pooling for authentication queries?
Yes, when the queries do not require database connection state to survive between transactions. PgBouncer 1.21 and later supports protocol prepared statements when max_prepared_statements is greater than zero. SQL PREPARE and persistent session features have different limitations. Check the driver and pooler configuration rather than disabling all prepared statements.
How do I prevent authentication data leakage between pooled connections?
Check the application user's access to every requested record. Avoid relying on persistent connection settings in transaction pooling. In session pooling, server_reset_query normally runs when the client releases its database connection and defaults to DISCARD ALL. That reset is normally skipped in transaction pooling. Connection cleanup does not replace tenant authorization.
Does PgBouncer affect authentication rate limiting?
Sharing database connections does not inherently merge rate limit counters. Identify each counter by the person, account, recipient, or request property being limited. Update counters atomically so simultaneous requests cannot lose increments. Do not identify the application user by the pooled database connection, and do not keep enforcement state only in persistent connection settings.