When to use PgBouncer
PgBouncer is generally recommended for OLTP workloads. All application connections should be routed through PgBouncer whenever possible. Learn more about the pros and cons of the different connection methods on the connections overview page. PlanetScale provides several options for using PgBouncer, including local PgBouncers, dedicated primary PgBouncers, and dedicated replica PgBouncers. PgBouncer connections operate in transaction mode, which means pooled server connections are assigned to client connections on a per-transaction level. This provides excellent performance for OLTP workloads but limits certain PostgreSQL features that require persistent connections. Learn more at the PgBouncer documentation.When to NOT use PgBouncer
For use cases that require long-running operations, direct connections on port5432 are recommended. For example:
- Schema changes and DDL
- OLAP, analytics, reporting, or batch processing
- Session-specific features: Custom session variables, temporary tables
- ETL processes and data streaming
- Long-running transactions or queries that span multiple transactions
- Creating a local backup with
pg_dump
Local PgBouncer
Every PlanetScale Postgres database includes an instance of PgBouncer running on the same node as the primary Postgres database (local PgBouncer). To connect to PgBouncer, use the same credentials as a direct connection, but use port6432 instead of the Postgres default of 5432. For example:
The local PgBouncer does not support routing queries to replicas. All connections through the local PgBouncer are automatically routed to the primary database, regardless of the username specification. Use a dedicated replica PgBouncer for replica access.
Dedicated replica PgBouncers
Dedicated replica PgBouncers can be created to run on nodes separate from the Postgres servers. This is useful for applications that send significant read traffic to replicas and need connection pooling. This offers similar high-availability benefits as the local PgBouncer but is used for read-only replica traffic.Creating a dedicated replica PgBouncer
You must be a database or organization administrator to create PgBouncers.- From the PlanetScale organization dashboard, select the desired database
- Navigate to the Clusters page from the menu on the left
- Choose the branch where you want to add a PgBouncer in the “Branch” dropdown
- Select the PgBouncers tab
- Scroll down to the “Dedicated replica PgBouncers” section
- Click the “Add a replica PgBouncer” button

- In the pop-up dialog, give the new PgBouncer a descriptive name. Note that names can not be modified after creation.
- Select a size based on your connection pooling needs (see PgBouncer pricing for available sizes)

- Click “Create PgBouncer”
- Wait a few minutes for the creation to complete
Availability zone affinity
Dedicated replica PgBouncers can be configured to prefer routing to the Postgres replica servers inside their own availability zone. Applications deployed across several zones can benefit from lower replica query latency in this configuration. However, if your application is deployed to a single zone, this mode may direct most queries to one replica server while replicas in other zones receive little traffic. Allowing the bouncer to load balance across availability zones, without preferring its own zone, will spread the query volume across the replica servers for single-zone applications. Select the Prefer routing to replicas in the same availability zone checkbox to enable affinity.Connecting to dedicated replica PgBouncers
Connect to dedicated replica PgBouncers by appending|pgbouncer-name to the username of any role you have created. For example, if your username is user1.abcdefghi and the dedicated replica PgBouncer is named read-bouncer, the connection username should be user1.abcdefghi|read-bouncer.
The hostname and password remain the same. Use port 6432 for dedicated PgBouncer connections:
Dedicated primary PgBouncers
A dedicated primary PgBouncer provides connection pooling for your primary database while running on nodes separate from the Postgres servers. Traffic flows from the dedicated primary PgBouncer to the local PgBouncer on the primary node, and then to Postgres. This extra layer lets client connections persist through cluster resizes, upgrades, and most failover scenarios, providing improved high availability. Primary bouncers are configured in the same way as replica bouncers. For production OLTP workloads requiring maximum availability, see the connection resilience guide.A dedicated pool runs multiple PgBouncers spread across availability zones for resiliency (configured with PgBouncers per availability zone). Connection-count settings such as
max_client_conn and default_pool_size apply to each PgBouncer in the pool, so the pool’s effective totals are the sum across all of them: the client-connection ceiling shown in the dashboard is the total across every PgBouncer (for example, three PgBouncers each with max_client_conn = 100 give a ceiling of 300), and total server connections to Postgres are likewise the sum of each PgBouncer’s default_pool_size. See Configuring PgBouncers.Connecting to dedicated primary PgBouncers
Connect to dedicated primary PgBouncers by appending|pgbouncer-name to the username of any role you have created. For example, if your username is user1.abcdefghi and the dedicated primary PgBouncer is named write-pool, the connection username should be user1.abcdefghi|write-pool.
The hostname and password remain the same. Use port 6432 for dedicated PgBouncer connections. For dedicated primary PgBouncers, requests route through the dedicated primary PgBouncer first, then the local PgBouncer, and finally Postgres:
Configuring PgBouncers
Each PgBouncer on the “PgBouncers” tab can be individually configured with a section like this under each PgBouncer:
Applying configuration changes
When you save a PgBouncer configuration change, PlanetScale applies it with a live reload. PgBouncer re-reads the updated configuration without a process restart. In normal operation, existing client connections are preserved during this reload, so applying configuration changes does not introduce downtime or a connection reset event.Configurable parameters
The following parameters can be configured for both the local and dedicated replica PgBouncers.Basic settings
Advanced settings
Advanced parameters should only be adjusted with a thorough understanding of PgBouncer internals.
Learn more about PgBouncer configuration on their official website.
How PgBouncer works
Connection reuse is the key mechanism that makes PgBouncer effective. When a client completes a transaction, PgBouncer returns the server connection to the pool rather than closing it. The next client transaction can immediately reuse that existing connection without incurring the overhead of spawning a new Postgres process. This allows a single pooled connection to serve hundreds or thousands of client connections over its lifetime, enabling applications to scale far beyond the constraints of direct connections.Pooling modes
PgBouncer supports three pooling modes, but PlanetScale-managed PgBouncers operate in transaction pooling mode only.- Transaction pooling: Assigns client connections to pooled server connections on a per-transaction level and allows multi-statement transactions. This mode provides the multiplexing benefits PlanetScale optimizes for and is the default on every PgBouncer we run.
- Statement pooling: Assigns client connections to pooled server connections on a per-query basis. This mode does not allow multi-statement transactions, which is unsuitable for most use cases.
-
Session pooling: Each client connection is given a dedicated connection from the PgBouncer pool for its entire duration. Because the mapping stays 1:1, Postgres connection counts do not decrease, connection limits are reached at the same rate, and PgBouncer adds another proxy layer that introduces latency. If your workload needs persistent sessions, connect directly to Postgres on port
5432instead of adding a PgBouncer hop.
Limitations of transaction pooling
PgBouncer’s transaction pooling mode provides excellent performance for OLTP workloads but limits certain PostgreSQL features that require persistent connections:- Prepared statements that persist across transactions (protocol-level prepared statements work with
max_prepared_statementsconfigured) - Temporary tables
LISTEN/NOTIFY- Session-level advisory locks
SETcommands that persist beyond a transaction

