36.3 Session Mode: Full Connection Ownership
Alright, let’s talk about Session mode. This is PgBouncer’s most straightforward, least-magical operating mode. It’s the one you reach for when you need to be absolutely sure your application’s connection semantics aren’t getting subtly butchered by a middleware proxy. The core concept is simple: in Session mode, PgBouncer gives your application what feels like a direct, dedicated connection to PostgreSQL for the entire lifespan of your database session.
Think of it like this: when your application asks for a connection, PgBouncer hands it a real, physical connection from its pool and says, “This one is yours. I’ve stamped your name on it. Don’t lose it.” It will hold onto that single backend process for you until you decide to disconnect. All your temporary tables, your prepared statements, your SET commands for the session—they’re all yours and they stick around exactly as if PgBouncer wasn’t even there. It’s basically just a fancy connection router.
Why You’d Use This “Boring” Mode
You use Session mode when your application depends on that session state. The big-ticket items are:
- Temporary Tables: You create a
TEMPORARY TABLEand you need it to persist across multiple transactions within the same session. In Transaction mode, that temp table would vanish the moment the transaction ended and the connection was returned to the pool. Session mode prevents that heartbreak. - Prepared Statements: You’re using prepared statements (
PREPARE,DEALLOCATE) without parameterized queries in your client library. These are session-scoped objects. If youPREPARE my_plan AS ...and then the connection gets yanked back to the pool and given to another client, well, that other client is going to be very confused when it tries toEXECUTE my_plan. - Session-Local Configuration: You’re using
SETto configure something likestatement_timeoutorsearch_pathfor the entire session and you need that setting to hold.
Here’s the catch: because PgBouncer locks a physical backend to your client’s session, your ability to handle more clients than you have backends is… zero. The pool size effectively becomes a hard limit on concurrent sessions. This is the trade-off. You get full PostgreSQL session semantics, but you lose the hyper-efficient over-subscription that makes PgBouncer so brilliant for massive scale.
The Nuts, Bolts, and Configuration
Configuring a pool for Session mode is dead simple. In your pgbouncer.ini, you just set it and forget it.
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb pool_mode=session
; ... or at the global level ...
[pgbouncer]
pool_mode = session
default_pool_size = 20
; Other settings...
From your application’s perspective, nothing changes. You connect to PgBouncer’s port instead of PostgreSQL’s port directly. The connection string is identical.
# Connecting with psql
psql -h 127.0.0.1 -p 6432 -U myuser mydb
The application has no idea it’s talking to a proxy. It just gets a connection that behaves exactly as expected.
The Gotchas and When to Avoid It
This is where my “brilliant friend” voice tells you the unvarnished truth. Session mode is safe, but it’s often a crutch. Before you default to it, ask yourself: Do I really need these session features?
Often, the answer is “no,” and you’re just shifting the connection management problem from PostgreSQL to PgBouncer without gaining the main benefit of PgBouncer (connection multiplexing). If you have 1000 application clients all holding onto sessions for long periods of time (like a typical web framework with persistent connections), you’ll still need 1000 backend connections on Postgres. PgBouncer becomes a single point of failure and an extra hop for no good reason.
The best practice is to treat Session mode as a specialized tool. Use it for:
- Legacy applications you can’t modify that rely on session state.
- Administrative tasks or one-off scripts where you need guaranteed session integrity.
- Specific workloads that genuinely, unavoidably need session-level features.
For the vast majority of web applications that are stateless and transaction-focused, you’re leaving performance on the table. You should be using Transaction mode, and we’ll get to that next. But for now, know that Session mode is your safe, predictable, and sometimes necessary option. It’s the training wheels that never come off—reassuring, but they’ll keep you from winning any races.