PostgreSQL connection pooling with PgBouncer

PgBouncer lets many application clients share a small set of PostgreSQL server connections. This page covers the pool mode decision, the application changes it forces, the build sequence, effort drivers and how to verify the result.

On this page

PostgreSQL connection pooling with PgBouncer: when teams need it and why it is harder than it looks

PgBouncer adds a lightweight connection pooler between application clients and PostgreSQL, but the hard part is application behavior, not installation. Teams usually reach for it when many application instances, container replicas or serverless workers each open direct connections to the database, and PostgreSQL starts to slow down or refuse logins under that load. These symptoms often appear after a traffic peak or a scale-out event, which makes them look like a database capacity problem. Before changing anything, count active and idle connections by client host and by application version. The fix depends on which clients are opening connections and how many they open.

Every PostgreSQL connection is served by a dedicated server process that carries real memory cost, whether or not it is doing work. Short-lived workers that connect, run a few queries and disconnect add setup overhead on top of that. PgBouncer keeps a smaller number of server connections open and lends them to client connections as needed. The pooling mode decides how much session state survives that lending. In session mode, a client keeps one server connection for its whole session. In transaction mode, the server connection returns to the pool after each transaction, so temporary tables, session variables, session-level advisory locks, LISTEN registrations and some prepared statement usage may no longer behave as the application expects. Inventory these features before choosing a mode.

There are two places to address connection growth. The application can cap its own pool size, which works per process and is easy to misjudge: each replica holds its own pool, so the total grows with every instance and every autoscaling event. The infrastructure layer places one pooler in front of the database and sets a single ceiling for all clients. Most production designs use both, with modest per-instance pools and a central pooler sized against the database's connection limit. The application must still tolerate the chosen mode, so the team should review ORMs, migration tools, background jobs and connection-level settings before cutover, not after the first incident.

Once PgBouncer is in the path, it becomes a new component that your team must patch, monitor and make highly available. A single pooler is a single point of failure for every client that depends on it, so plan redundancy and a way to repoint clients if one fails. Track release notes for security fixes. PgBouncer 1.26.1, released October 14, 2026, included security fixes, so confirm the version you run against the project's site before go-live. Monitor client wait time, pool saturation and rejected connections, and confirm that TLS and authentication are configured on both the client-to-pooler and pooler-to-server connections. Ask any implementation partner to show these checks in the written scope.

Which PgBouncer pool mode and topology to choose

This table compares PgBouncer's session, transaction and statement pool modes, then a single pooler against one pooler per application, along with the features each choice keeps or breaks. Read each row against your application's database usage, and treat the main takeaway as a reason to audit the code before choosing transaction pooling.

OptionWhat it fitsWhat it preserves or breaksOperational cost
Session pool modeApplications that hold a server connection for a whole client session and need full PostgreSQL session behaviorPreserves SET, temporary tables, prepared statements, advisory locks and LISTEN/NOTIFY, but gives little multiplexing gainLow review effort; main cost is capacity planning as client count grows
Transaction pool modeShort, stateless transactions from many web or API clients where most connections sit idleBreaks session state, session-level advisory locks, SET without LOCAL and temporary tables across transactions; prepared statements need checkingHighest review effort: audit ORM and driver settings, then test every flow that touches session state
Statement pool modeNarrow workloads of single autocommit statements with no multi-statement transactionsBreaks multi-statement transactions and most session features; rarely fits general application codeLowest fit for typical applications; expect ongoing workarounds and frequent exceptions
Single shared poolerSmall estate with few applications and one team owning connection settingsOne place to tune and monitor, but a shared pool mode forces every application to tolerate the most restrictive modeLower footprint; more cross-team coordination when one application needs a different mode
One pooler per applicationApplications with different pool modes, credentials or change schedulesLets each application use the mode it needs, including session mode for legacy codeMore components to deploy, patch, monitor and document; more configuration drift risk
Authentication via auth fileTeams that want PgBouncer to hold user credentials and map them to PostgreSQL loginsAdds a credential store to rotate and protect; confirm supported hash formats in the release notes for your versionRecurring work to rotate passwords in the file and keep it synchronized
Authentication via passthrough to PostgreSQLEnvironments using PostgreSQL's own authentication methods, such as SCRAM or certificatesKeeps credentials in PostgreSQL; confirm the passthrough setup and supported methods for your PgBouncer releaseRecurring review of the authentication configuration; fewer secrets to store on the pooler

Which application features break under transaction pooling

Transaction pooling is the mode most teams choose when they want PgBouncer to share a small set of PostgreSQL server connections among many clients, and it is also the mode that breaks application code without warning. In this mode PgBouncer assigns a server connection to a client only for the duration of a transaction, then returns it to the pool. The next transaction from the same client may run on a different backend process. Anything that stores state on the server connection, rather than inside a transaction, can therefore appear to work in testing and fail intermittently in production, depending on which backend happens to serve each request.

The features most often affected are session-level SET and RESET commands, session-scoped advisory locks (pg_advisory_lock, as opposed to the transaction-scoped variant), temporary tables, cursors declared WITH HOLD or otherwise kept open across transactions, LISTEN and NOTIFY subscriptions, and server-side prepared statements. A SET issued in one transaction may be invisible to the next one. A session advisory lock may be acquired on one backend and never released by the client that expects it. A temporary table created in one request may not exist in the next. LISTEN registrations are tied to a backend, so notifications may be delivered to a connection the client is no longer using. Prepared statements are the subtle case: drivers and ORMs often prepare a statement once and reuse its name on every later call, so a request that lands on a backend without that statement fails with an error about a missing prepared statement.

Inventory before switching modes. Start with the codebase and the driver configuration, not the database. Search for SET and SET SESSION, RESET, pg_advisory_lock, CREATE TEMP or TEMPORARY TABLE, DECLARE with HOLD, LISTEN and NOTIFY, and any call that names a prepared statement. Then check the ORM and driver settings: many libraries have a switch that disables or changes server-side prepared statement caching, and some enable it by default. Ask each application team to confirm which features they use and whether any framework, migration tool or background job issues session commands on their behalf. Record the result per service, because one legacy job can force a whole pool into session mode.

Decide what must change. Session-scoped state should be rewritten as transaction-scoped state where possible: use SET LOCAL inside a transaction, pg_advisory_xact_lock in place of session locks, and ordinary tables or CTEs instead of temporary tables that must persist across requests. Cursors and LISTEN loops generally need a dedicated connection, so they belong on a separate pool or a direct connection in session mode. Prepared statements usually need either disabling client-side caching or moving the affected services to a session-mode pool. The right split depends on how many services are affected and how much rewriting the team can absorb, so treat it as a scoped decision recorded before cutover.

Verify the result. Run the integration suite through PgBouncer in transaction mode with a pool small enough to force connection reuse, since larger pools hide the problem. Confirm with the vendor documentation for each driver and ORM how its prepared statement cache behaves under transaction pooling and which version introduced the setting you plan to use. Illustrative example: a service sets a search_path with a plain SET at login, then runs a report that reads unqualified table names; under transaction pooling the report sometimes queries the wrong schema. A SET LOCAL inside the report transaction removes the dependency. Ask the PgBouncer documentation for the current list of supported settings before you rely on any of them.

Setting up PostgreSQL connection pooling with PgBouncer, step by step

This sequence takes a PostgreSQL deployment from direct client connections to PgBouncer in front of it, one application at a time. Each step ends with a check you can confirm before the next step begins. The order matters because the pool mode and authentication choices depend on the baseline and the feature inventory.

  1. Confirm PostgreSQL version and connection baseline

    The team records the PostgreSQL major version and checks it against the supported release list, since version 14 leaves community support on November 12, 2026. Next, it counts current connections, peak concurrency and idle sessions from pg_stat_activity, and confirms how logins authenticate today, such as SCRAM, MD5 or certificates, using the rules in pg_hba.conf. Ask the database owner to supply these numbers before any sizing decision is made. The step is done when the team holds a written baseline covering version, peak client connections and authentication methods in use.

  2. Inventory application pooling and session features

    Each application team lists how it pools connections today and whether it relies on session state. Typical dependencies include SET commands, temporary tables, advisory locks, LISTEN and NOTIFY, WITH HOLD cursors and server-side prepared statements. These features tie work to a single server session, so they can fail when PgBouncer reuses a server connection between transactions. Record the framework, driver and pool library versions as well. The step closes when each application has a signed-off list naming the pooling mode it can tolerate.

  3. Install a supported PgBouncer release

    Install PgBouncer 1.26.1, the current release in the researched facts, which was released on October 14, 2026 and includes security fixes. Use an operating system package or a build from the project site, and pin the version in configuration management so upgrades happen deliberately. Run the service under a dedicated account with restricted access to the configuration and authentication files. If your distribution packages an older build, confirm with the packager before relying on it. Check: pgbouncer --version reports 1.26.1 and the service starts without errors in the system log.

  4. Map databases and users in pgbouncer.ini

    Define a [databases] section that maps each client-facing database name to its host, port and database name on PostgreSQL, so applications keep their existing names during cutover. Set listen_addr and listen_port, and list the administrative users allowed into the PgBouncer console. Keep pgbouncer.ini in version control and have the database owner review it. Check: a psql connection to the PgBouncer port reaches the intended database, and SHOW DATABASES in the admin console lists every mapping you defined.

  5. Choose auth file or auth_query

    Decide how PgBouncer validates clients. An auth file holds usernames and password hashes copied from PostgreSQL, and it must be refreshed whenever credentials change. With auth_query, PgBouncer looks up the hash in PostgreSQL through a dedicated, least-privilege role, which removes the separate file to maintain. Match the choice to the authentication method in use, and confirm in the PgBouncer documentation for your version which hash formats are forwarded. SCRAM is the stronger option, since PostgreSQL 18 deprecated MD5. Check: each role logs in successfully through the pooler, and a wrong password is refused.

  6. Set pool mode and limits per workload

    Select pool_mode for each database. Transaction mode gives the most connection reuse but breaks session state, so applications that depend on session features need session mode. Set default_pool_size, max_client_conn and reserve_pool_size against PostgreSQL max_connections, leaving capacity for administrators and replication. Derive pool sizes from the measured baseline and load test results, then check them against the number of application instances. Check: under a load test, SHOW POOLS shows waiting clients staying near zero, and server connections stay below max_connections with headroom.

  7. Enable TLS where policy requires it

    Where policy requires encryption, configure PgBouncer to accept TLS from clients and to connect to PostgreSQL over TLS, using certificates issued by your internal certificate authority. Set the client-side and server-side TLS modes deliberately, and confirm that the pg_hba.conf rules on PostgreSQL match the connection types PgBouncer uses. Certificate issuance, renewal and rotation become part of the operations runbook. Check: a psql session through the pooler reports an encrypted connection, and a plaintext attempt is refused wherever policy forbids it.

  8. Test and cut over one application

    Point a non-production copy of one application at the pooler and run the feature tests from the inventory alongside its integration suite. Cover connection churn, prepared statements, transactions that depend on session state and batch jobs. Failures usually mean a feature needs session mode or a direct connection. Once the suite passes, move production traffic for one application at a time, watching SHOW POOLS and SHOW STATS during each move and keeping a documented rollback to the direct connection string. Check: each application completes a full business cycle through the pooler with error rates unchanged from the baseline.

What drives the effort and cost of PgBouncer pooling

This table lists the factors that change how much work a PgBouncer deployment takes, which parts are paid once and which recur, and how to reduce each one. Use it to see where your environment sits before asking a partner for a written quote. The main takeaway is that application code and authentication design usually decide the effort more than the PgBouncer installation itself.

DriverWhy it changes effortOne-time workRecurring workHow to keep it down
Number of applications and languagesEach client stack handles pooled connections, timeouts and errors differently, so every application needs its own test pass.Inventory of connection strings, driver versions and pool settings per application, plus per-application testing.Keeping driver versions and pool settings aligned as applications change.Standardize on a small set of drivers and one pool configuration template.
Session state and prepared statement useSession-level features such as SET, temp tables, advisory locks and named prepared statements break or behave unexpectedly in transaction pooling mode.Auditing code for session state, rewriting or isolating affected paths, choosing a pooling mode per workload.Reviewing new code for session state before it reaches production.Keep session-dependent workloads on a separate pool or direct connection, and document the rule for developers.
Number of databases and rolesEach database and login role needs its own pool entry, authentication rule and sizing decision.Mapping databases and roles to pools, writing the PgBouncer configuration and access rules.Adding pool entries when a new database or role appears.Generate configuration from a single source of truth and limit who can create roles.
Central identity and authenticationMoving logins to LDAP, GSSAPI, certificates or OAuth changes how PgBouncer and PostgreSQL both validate clients.Confirming which methods PgBouncer supports for your version, testing each path, and agreeing the role mapping.Maintaining identity provider settings and certificate or ticket renewals.Confirm supported methods with the PgBouncer and PostgreSQL documentation before design, then test each path once.
TLS requirementsEncryption on client-to-pooler and pooler-to-PostgreSQL links adds certificate management and verification steps.Certificate issuance, trust chain setup, and testing of verification modes on each link.Certificate rotation and expiry monitoring on both links.Reuse your existing certificate authority and automate renewal.
High availability of the poolerA single PgBouncer is a single point of failure, so a redundant pooler pair or virtual IP adds components to build and test.Designing the pooler layer, failover behavior and client reconnection tests alongside PostgreSQL high availability.Patching and health checks for each pooler instance, and failover drills.Decide early whether pooler redundancy is required and test client behavior during a pooler restart.
Number of environmentsEach environment needs its own configuration, test run and promotion path, and drift between them causes incidents.Building environment-specific configuration and a promotion process.Keeping configuration in sync and reviewing differences between environments.Use one templated configuration and promote it through the same pipeline.
Change control and compliance evidenceAssessors and internal reviewers may ask for records of configuration changes, access rules and test results.Defining the evidence set, such as configuration history, approvals and test records, and how it is stored.Producing evidence for each change and for periodic access reviews.Keep configuration in version control and link each change to an approved request. DeployOpen prepares evidence, but auditors and certification bodies issue any attestation.
Upgrades of PgBouncer and PostgreSQLPgBouncer releases fixes, including security fixes, and PostgreSQL minor releases require pooler compatibility checks.Baseline testing of the chosen PgBouncer version against your applications.Applying PgBouncer updates on your chosen cadence and rechecking pool behavior after each PostgreSQL upgrade.Track PgBouncer release notes and schedule updates with PostgreSQL minor release windows.

How pooling changes on a single node, in HA, on Kubernetes and in air-gapped networks

On a single PostgreSQL primary with one PgBouncer, the pooler sits between application clients and one database server. The failure domains are simple: if PgBouncer stops, clients lose their path to the database, and if PostgreSQL stops, the pooler offers no protection. Most of the configuration work is about the pool mode, the server-side pool size and the client connection ceiling, all measured against the connection limit set on PostgreSQL.

  • Pool sizing: Set the server-side pool against PostgreSQL max_connections, leaving headroom for administrative sessions and maintenance jobs.
  • Load profile: Confirm the CPU and memory the chosen PgBouncer version needs under peak client load, and test that profile before go-live.
  • Process supervision: Run PgBouncer under a service manager with a restart policy, and monitor it separately from PostgreSQL.
  • Client endpoint: Applications connect to the pooler port, so every connection string changes at cutover.
  • Admin access: Restrict the PgBouncer administration console to named operator accounts.

Before going live, check that a pooler restart is tolerable for your applications and that their retry behavior handles dropped connections.

Securing the PgBouncer layer and its credentials

PgBouncer sits between every application and the PostgreSQL primary, so it becomes a trust boundary for client identities, server credentials and its own administrative interface. The cards below cover one control each, with the check that shows it is in place, so a reviewer can verify the pooler the same way they verify the database.

Client-to-pooler TLS

Enable TLS on the listening side so application connections are encrypted before they reach PgBouncer, and set the client TLS mode to require encrypted connections for any network segment that crosses a trust boundary. Check the setting by connecting from an application host with SSL disabled and confirming the connection is refused, then confirming the server certificate chain validates from a client that enforces verification.

Pooler-to-server TLS

PgBouncer opens its own connections to PostgreSQL, and those hops also need encryption if they leave a single trusted host. Configure the server-side TLS mode to match your policy, and decide whether the pooler verifies the PostgreSQL certificate against a CA file. Check it by capturing a pooled connection to the server and confirming the session reports SSL in use, and that a server with an untrusted certificate is rejected.

Authentication method matched to PostgreSQL

PgBouncer can only authenticate clients with methods it implements and must agree with the server's pg_hba.conf rules. Use SCRAM password authentication where the server supports it, because MD5 password authentication is deprecated in PostgreSQL 18 in favor of SCRAM. Where you need certificates, LDAP, GSSAPI or OAuth, confirm with the PgBouncer version you deploy (the current release is 1.26.1) which methods it supports before you commit the design.

Auth file hash storage and rotation

The userlist or auth file holds credentials the pooler uses to log clients in, so store only password hashes in it, never plaintext, and restrict the file to the PgBouncer service account. Document a rotation procedure that updates the hash, reloads the pooler and confirms old credentials stop working. Check file permissions and confirm that a rotated password is refused by a test login.

Least-privilege roles for the admin console

The pooler exposes a virtual administrative database that can pause, resume and reload pools, and it should not be reachable with the same credentials as application roles. Create a dedicated monitoring or administration user, grant it only the admin rights the operations team needs, and restrict who may use it. Check that an application login to the admin database is rejected and that the admin account cannot read application tables.

Restricting access to the admin database

Limit which hosts can open the admin database by setting the admin_users and stats_users lists and by allowing connections to the pooler's management port only from a jump host or monitoring network. Because the console can alter live pool behavior, treat its access list as a change-controlled record. Check it by attempting a connection from an unlisted host and confirming it fails and is logged.

Network placement of the pooler

Place PgBouncer close to the application tier and on a network path that only the application subnets and administrators can reach, with the PostgreSQL primary accepting connections only from the pooler's address. Keep the pooler off public networks and document the firewall rules on both sides. Check the placement by testing reachability of the database port from an application subnet, a public address and a host outside the pooler's allowed list.

Secrets in configuration management

The pooler configuration and auth file often end up in version control or automation variables, which turns a password into a repository leak. Keep credentials in a secrets store, render the files at deploy time with restricted permissions, and exclude rendered output from source control. Check it by searching the configuration repository and build logs for password hashes and plaintext values, and by confirming the deployed file is readable only by the service account.

How to verify PostgreSQL connection pooling with PgBouncer before cutover

The verification plan should prove that PgBouncer changes where client connections land, but not what the application does with the data. Start from the application feature inventory. Every feature that opens connections, runs multi-statement transactions, uses session state or depends on prepared statements gets a functional test that runs through the pooler and the same test against a direct connection. Compare more than pass or fail. Compare returned values, error codes, row counts and final table contents. Session-level behavior deserves particular attention, because temporary tables, session variables, advisory locks, LISTEN and NOTIFY, and prepared statements can behave differently depending on the pool mode. Confirm against the documentation for the PgBouncer version you plan to deploy which features your chosen mode supports, and write tests for each feature that the mode does not support.

Load tests should reproduce the peak client count taken from the application inventory, plus a margin the team agrees on before the test starts. Run each test long enough for the pool to reach steady state, and watch PgBouncer's own statistics for client wait time, active and idle server connections and the number of clients queued for a server connection. The purpose is to confirm that queueing is predictable: latency rises in a controlled way, clients wait instead of failing, and the pool never pushes PostgreSQL past its configured connection limit. Repeat the run with a smaller pool to show how the sizing decision in the change record behaves at the edge. Include a few long-running transactions in the mix, because they can hold server connections and starve short requests if the pool is sized too tightly.

Failure tests should cover four events: a PgBouncer restart, a PostgreSQL restart, dropped server connections (for example, terminating backend processes with administrative commands) and expired or rotated credentials. Before each run, write down the expected client behavior. A safe pool returns clear connection or query errors that the application logs, and it retries only where the transaction is safe to repeat. It must not return stale results, duplicate writes or a commit the client believes failed. After each event, run the same reconciliation queries used in functional testing and compare the database state with the transaction log kept by the test harness. The rollback test is the last failure test: move each application back to direct connections, repeat the functional checks, and confirm that stopping the pooler leaves no residual effect on the database or the applications.

To prove that the cutover did not change transaction outcomes, run a fixed set of business transactions with identical inputs, once through the pooler and once directly, and compare commit or rollback status, returned values and the resulting table state. Store the test scripts, PgBouncer and PostgreSQL versions, configuration files, pool settings, timestamps, results and sign-offs in the change record. Record every deviation with its cause and the approver who accepted it. Confirm with the security and compliance owners which evidence they need, including who ran the tests and where the raw output is kept, so the record can be reviewed after the change without rerunning anything.

Questions buyers ask before hiring help with PostgreSQL connection pooling

Can our team set up PgBouncer ourselves without outside help?

Yes, for a simple setup with one application, one database and a clear list of how the application uses connections, an experienced PostgreSQL team can usually add PgBouncer on its own. The main risk is the feature inventory. Before you change anything, list every place the application relies on session state: prepared statements, advisory locks, SET commands, temporary tables, LISTEN and NOTIFY, and session-level settings. Those features behave differently under transaction pooling. If the inventory is long, if several applications share one database, or if the code uses an ORM or driver that caches session state, a partner can reduce the chance of an outage that only shows up under load. Ask your own team to check this list first, then decide.

What drives the cost and effort of a PgBouncer engagement?

Effort depends mostly on how many applications connect, how many databases and roles they use, and how much application code or driver configuration has to change. Each application adds a test cycle, and each session-dependent feature adds analysis and possibly code work. Other drivers include the pooling mode you choose, how many environments need to be built and tested, whether monitoring and alerting for the pooler are in scope, and how many change windows are available for cutover. The cost you pay is for analysis, configuration, testing and handover, and the one-time work usually dominates. Recurring costs are mainly the time to maintain PgBouncer versions and review pool settings as load changes. A quote should break these items out and name which applications are included.

How long does a PgBouncer implementation take?

The duration depends on the number of applications connecting to the database and on how much code or driver configuration needs to change. A single application that already uses plain connections can move quickly, while several applications with session-dependent features need more analysis and test cycles. Test sign-off and the availability of change windows often set the pace more than the installation itself. DeployOpen does not publish a fixed timeline for this topic. The duration is set in the written scope, which lists the applications, environments and deliverables, and it should be agreed before work starts. Ask for the timeline to show the testing and change window steps separately.

What do we need to provide for a PgBouncer engagement?

The work needs access to the application code or to the people who own it, so that connection use and driver settings can be reviewed. It also needs the driver configuration for each application, access to non-production environments that resemble production, and agreed change windows for cutover and rollback. Most important is a named owner who signs off test results for each application. Without that person, testing stalls and the cutover date slips. You should also provide the current pool and connection limits in PostgreSQL, a list of applications and their connection patterns, and a point of contact for monitoring data. Confirm these items in the scope before the engagement starts.

Does PgBouncer replace PostgreSQL high availability?

No. PgBouncer is a connection pooler. It reduces the number of server connections PostgreSQL has to manage, but it does not detect a failed primary, promote a standby or move traffic to a new primary by itself. PostgreSQL does not provide software to detect a primary failure and notify a standby either, so automatic failover requires external tools and a tested design. If you need failover, plan it as a separate piece of work with replication, a failover manager and a tested switchover procedure, and place PgBouncer in front of that design. Ask any partner to show how the pooler's configuration changes during a failover, because a pooler pointed at a failed host will not recover on its own.

Which PgBouncer version should we install?

Confirm the current release and its security notes with the PgBouncer project before you install anything. The project site publishes release information, and at the time this page was prepared the release history included version 1.26.1, released on October 14, 2026, with security fixes. Do not assume that a version in a distribution package is current. Check the release notes for changes in pooling behavior, configuration options and supported PostgreSQL versions. Record the version you deploy, and set a process to review security releases as they are published. The version choice should be part of the written scope so that testing covers the version that goes to production.

Which PostgreSQL versions does a PgBouncer setup need to support?

PgBouncer sits in front of PostgreSQL, so the PostgreSQL version you run affects how you test the setup. Supported PostgreSQL major versions at the time of writing are 18, 17, 16, 15 and 14, and versions 13 and earlier are no longer supported. Confirm the end-of-life dates in the PostgreSQL versioning policy before you choose a target. If you plan a major upgrade in the same period as the pooler change, test both changes together or separately, and keep the pooler configuration documented so that the upgrade test environment can be rebuilt. Ask your partner whether the test plan covers the PostgreSQL version you actually run in production.

What to monitor, back up, upgrade and document after pooling goes live

Watch five things after go-live: client connections, server connections, wait queues, PgBouncer's administrative statistics, and authentication errors. The PgBouncer admin console, reached through a virtual database named pgbouncer, exposes SHOW CLIENTS, SHOW SERVERS, SHOW POOLS and SHOW STATS. A sustained count of waiting clients in SHOW POOLS means the pool is too small for the workload or that transactions hold server connections too long. Trend query and transaction rates and wait times from SHOW STATS so that changes in application behavior appear before users report them. Authentication failures show up in the PgBouncer log and the PostgreSQL log, and a sudden rise often follows a password rotation or an edit to the auth file. On the PostgreSQL side, compare server connections against max_connections and watch memory per backend, since each pooled server connection is still a backend process. Confirm exact column names and log messages against the PgBouncer version you run.

Back up the configuration and auth file. The PgBouncer configuration file and the authentication file are part of your recovery set. With those two files, plus any definition of the auth_query role, you can rebuild the pooler on a new host with the same databases, users and settings. Keep them in version control or your configuration management system, and handle password hashes and secrets under your existing secret-management policy. Pooled session state does not need backup. Client sessions and server connections are transient, and PgBouncer holds no application data. PostgreSQL backups remain the data protection layer, as covered in the backup and recovery design. Until you have restored the pooler from the stored files in a non-production environment and confirmed that an application connects and authenticates, the backup is only an assumption.

Treat pool sizes as controlled configuration. The settings that matter most are default_pool_size, max_client_conn, max_db_connections and the per-database and per-user pool limits. Each one caps how many server connections PgBouncer can open, and the combined total must fit inside PostgreSQL's max_connections with room left for administrative sessions, replication and maintenance. Record every change in a ticket with the reason, the expected effect on wait queues, the owner, and the previous value for rollback. Test changes in staging under a load profile that resembles production. A larger pool can move the bottleneck to database CPU or memory, so judge each change by database health as well as by queue length. Ask your team to define who may approve an increase before the first incident forces the question.

Plan PgBouncer upgrades as security maintenance, separate from PostgreSQL minor releases. Version 1.26.1 was released on October 14, 2026 with security fixes, so any installation running an earlier release should be reviewed promptly after you read the release notes. Subscribe to the project's announcements, read the changelog for configuration changes, and confirm in staging that your configuration file still loads on the new binary. Keep the previous binary and configuration on hand so rollback is a package or file swap followed by a restart. Because PgBouncer sits in the client connection path, coordinate the restart with the application team and confirm that clients, including those with long-lived connections, reconnect cleanly. Record the installed version in your inventory so that future advisories can be matched to your estate quickly.

Major PostgreSQL upgrades change how the pooler and the application behave, even when PgBouncer itself does not change. After a major upgrade, rerun the application feature tests that pooling can break. Prepared statements, session-level SET commands, LISTEN and NOTIFY, advisory locks, temporary tables and session-scoped settings all depend on which server connection a client receives. Confirm the authentication path as well. PostgreSQL 18 deprecated MD5 password authentication in favor of SCRAM, so check that the auth file hashes and client drivers match the method your pg_hba.conf enforces. Run these tests through PgBouncer, because that is the path production traffic takes. Finally, hand over five documents before the pooler is treated as operational: an architecture diagram, a pool mode rationale, an application feature inventory, a restart and rollback runbook, and an ownership record that names who maintains the configuration, who is on call, and who approves pool size changes.

How DeployOpen scopes, builds, hands over and supports PgBouncer pooling

DeployOpen plans, implements, documents and supports self-hosted open-source platforms inside your own infrastructure, including PostgreSQL connection pooling with PgBouncer. The pooler, its pool modes and its limits are designed around how your applications use connections, then deployed in your cloud accounts, data centers or air-gapped network. Engagements are fixed-scope, with scope and deliverables agreed in writing before work starts.

How we scope

  • The written scope names the applications, client connection counts and pool modes covered by the engagement.
  • Scope records which PostgreSQL clusters sit behind PgBouncer and where each pooler will run.
  • Engagements are fixed-scope, and ongoing support is available as a retainer after handover.

How we build

  • Install PgBouncer in your environment and configure listeners, authentication and pool limits per database.
  • Test each pool mode against the application's use of session state, prepared statements and transactions.
  • Load test pool sizing against PostgreSQL max_connections and document the chosen limits.

How we hand over

  • Deliver configuration files, pool mode decisions and the reasoning behind each sizing choice in writing.
  • Provide runbooks for adding databases, rotating credentials and reading PgBouncer admin console statistics.
  • Walk operations staff through failure cases, including what happens when a backend connection drops.

How we support

  • Retainer support can cover PgBouncer version upgrades, including applying security fixes on release.
  • Review pool configuration when application releases change transaction patterns or connection volumes.
  • Confirm support boundaries, response expectations and change control in the written agreement before work starts.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.