PgBouncer vs Pgpool-II: which one belongs in front of your cluster
Choose PgBouncer when your main problem is connection overhead and you want a single-purpose pooler with a small memory footprint. PgBouncer offers session, transaction and statement pooling modes and needs about 2 kB of memory per connection by default, according to the PgBouncer features page. Choose Pgpool-II when you also want the pooler to distribute read queries across several PostgreSQL servers, remove failed servers automatically and coordinate several Pgpool-II instances through its watchdog. The Pgpool-II documentation lists all of these as core functions, so the choice is about how much of the cluster you want one layer to own. The decision turns on three questions: whether your applications tolerate transaction pooling, whether a separate HA manager already handles failover, and which team will operate the layer.
Start with application compatibility. The PgBouncer features page warns that transaction pooling breaks client expectations of the server by design, so applications must avoid features such as SET and RESET, LISTEN, and PREPARE and DEALLOCATE. Audit your code, ORM settings and connection libraries for session state, advisory locks and server-side prepared statements before you pick transaction mode. If the audit finds heavy use of these features, session mode is safer but gives less pooling benefit. Pgpool-II also multiplexes connections, so it carries similar compatibility questions, and you should test both against your real workload rather than a synthetic benchmark.
Next, decide where failover lives. PostgreSQL does not detect a primary failure or promote a standby by itself, so automatic failover needs external tools, according to the PostgreSQL failover documentation. If Patroni or CloudNativePG already promotes the primary, PgBouncer can sit in front of the cluster and point at a changing endpoint, which keeps the pooler simple. If you want Pgpool-II to handle failover and read routing, plan for the watchdog and a second operational system to test and monitor. In either case, confirm with your vendor or your own test lab how each layer behaves during a failover, and write that behavior into your runbook.
Which pooler fits which PostgreSQL scenario
This table maps common PostgreSQL scenarios to the pooler that usually fits best, with the condition under which the other option would be preferred. Read each row as a starting point, then check it against your application's use of session features and your existing HA tooling.
| Scenario | Better fit and reason | Prefer the other option when |
|---|---|---|
| Many short-lived connections from a few stateless applications | PgBouncer. It is a lightweight pooler that uses about 2 kB of memory per connection by default, and transaction pooling multiplexes many clients onto few server connections. | You need read distribution or failover logic in the same layer, and your applications can tolerate Pgpool-II's additional processing. |
| Patroni-managed cluster that already has an HA manager | PgBouncer in front of the primary endpoint. Patroni handles leader election and failover, so a pooler that only pools keeps the failure domain small and easier to reason about. | Your design requires Pgpool-II's watchdog or automatic removal of failed servers and you have deliberately chosen not to use Patroni's endpoint routing. |
| Read traffic must spread across hot standbys | Pgpool-II. It distributes read queries across multiple PostgreSQL servers, which PgBouncer does not do. Confirm that your application can tolerate replication lag on reads. | Reads can go to a separate endpoint or client-side routing already exists, or you want a pooler with a narrower feature surface. |
| Legacy applications that use session features | PgBouncer in session pooling mode, or direct connections. Transaction pooling breaks SET/RESET, LISTEN and PREPARE/DEALLOCATE expectations, so session mode is the safer choice for these workloads. | Session mode still yields too many server connections, and you can refactor the application to avoid session state before moving to transaction mode. |
| One tool for both pooling and failover | Pgpool-II, since it bundles connection pooling, read load balancing, failed-server removal, watchdog coordination and online node recovery. Confirm how it behaves in your failover tests before relying on it. | You already run a dedicated failover manager such as Patroni or repmgr, or you want each layer to have a single responsibility that your team can operate independently. |
| Team that wants minimal moving parts and clear failure modes | PgBouncer. A single-purpose pooler is simpler to configure, monitor and explain to auditors than a multi-function middleware layer. | Your operational requirements include coordinated multi-instance pooling with failover behavior managed in one product. |
How PgBouncer and Pgpool-II are built and what that means for operations
PgBouncer and Pgpool-II both sit between applications and PostgreSQL, but they are built for different jobs and fail in different ways. The cards below cover what each component does, where it runs, and which parts you monitor, patch and recover separately. Confirm the deployment topology for your own environment before choosing either one.
PgBouncer as a single-purpose pooler
PgBouncer does one job: it multiplexes client connections onto a smaller set of server connections. It offers session, transaction and statement pooling modes, and by default needs about 2 kB of memory per client connection. Operationally, you watch client and server connection counts, wait queues and pool saturation, and you can upgrade it without touching the database servers. Confirm which pooling mode your application can tolerate before you deploy it.
Pgpool-II as a combined middleware layer
Pgpool-II bundles connection pooling, distribution of read queries across several PostgreSQL servers, automatic removal of failed servers and a watchdog that coordinates multiple Pgpool-II instances. These roles share one process layer, so a configuration change for read routing can affect pooling and failover behavior too. Check how read distribution interacts with your replication lag, and test the watchdog failover path before relying on it in production.
The external failover tool PostgreSQL requires
PostgreSQL does not detect a primary failure or promote a standby on its own, so automatic failover needs an external tool regardless of which proxy you choose. Neither PgBouncer nor Pgpool-II replaces that tool in a design where the cluster must promote a new primary and repoint clients. Identify the tool, its consensus or configuration store, and who owns its runbooks. Pooler configuration then has to follow the tool's promotion events.
Placement relative to the database servers
PgBouncer is commonly placed on the application hosts, on a dedicated host, or beside the database nodes, and each choice changes what fails together. A pooler on the database host shares its CPU, memory and failure domain with PostgreSQL, while a separate pooler adds a hop and another component to patch. Pgpool-II is usually deployed as its own tier with watchdog peers, which adds instances to monitor and to keep at matching versions. Confirm the placement, the number of instances and the upgrade order in writing with your platform team.
What transaction pooling breaks in your application code
Transaction pooling breaks client expectations of the server by design, and the PgBouncer features page says so directly. In transaction mode a server connection is handed back to the pool when a transaction ends, so the next transaction from the same client may run on a different backend. Anything that depends on session state therefore has to be removed or moved inside a transaction. The features named as off limits are SET and RESET for session parameters, LISTEN for notifications, and PREPARE and DEALLOCATE for named prepared statements. Session-level advisory locks, temporary tables that outlive a transaction and session-scoped SET ROLE fall into the same category, and the features page is the authoritative list to check against your PgBouncer version.
Start the audit with the code and the ORM configuration, not with the database. Search the repositories for SET , RESET, LISTEN, PREPARE and DEALLOCATE, and review how your driver and ORM handle named prepared statements, since many enable them by default. Look at connection startup parameters and pool settings that set search_path, time zones or application names once per connection, because those values may silently disappear when the backend changes. Check any migration tooling and batch jobs that open long sessions. Where a dependency cannot be changed, ask the vendor or project how to disable its prepared statement cache or session setup before you route it through transaction pooling.
Session pooling is the safer choice when an application depends on session state and cannot be refactored soon, such as legacy code, admin tools or workloads that rely on LISTEN. Statement pooling is the most restrictive mode and suits only single-statement, autocommit workloads, so most teams that start with it hit problems quickly. Pgpool-II also pools connections and can route statements, but how it treats SET, LISTEN and prepared statements is not something to assume. Confirm that behavior in the Pgpool-II documentation for the exact version you plan to run, and test your own workload against it before choosing either tool.
PgBouncer vs Pgpool-II feature by feature
This table sets PgBouncer and Pgpool-II side by side on pooling, read distribution, failure handling and high availability coordination. Read each row as a question about your cluster: rows where a cell says to confirm mean the supplied documentation does not settle the answer, so check the vendor docs before you decide.
| Capability | PgBouncer | Pgpool-II |
|---|---|---|
| Connection pooling | Core function. Pools client connections in front of PostgreSQL servers. | Documented feature. Pools connections as part of a broader proxy layer. |
| Pooling modes | Session, transaction and statement modes. Transaction mode restricts SET/RESET, LISTEN and PREPARE/DEALLOCATE. | Confirm the pooling behavior and any session-state restrictions in the Pgpool-II documentation for your version. |
| Memory per connection | About 2 kB by default, according to the PgBouncer features page. | Not covered by supplied facts. Confirm sizing guidance with the Pgpool-II documentation. |
| Read query distribution | Not a feature. PgBouncer routes connections, not read queries across standbys. | Distributes read queries across multiple PostgreSQL servers. |
| Automatic removal of failed servers | Not a documented feature in the supplied facts. Confirm with the PgBouncer documentation. | Documented. Failed servers are removed automatically from the pool. |
| Watchdog coordination | Not a feature. PgBouncer does not coordinate peer instances for high availability. | Documented. The watchdog coordinates multiple Pgpool-II instances. |
| Online recovery of a node | Not a documented feature in the supplied facts. Confirm with the PgBouncer documentation. | Documented. A failed node can be brought back online with one command. |
| Failover detection | Not a feature. PostgreSQL itself does not detect primary failure, so external tools are needed for automatic failover. | Failed-server removal is documented. Confirm how promotion of a new primary is handled in your configuration with the Pgpool-II documentation. |
Licensing and editions for each pooler and the PostgreSQL core
PostgreSQL is released under the PostgreSQL License, a liberal open source license similar to the BSD or MIT licenses. In practice this means you can run, modify and redistribute it inside your own infrastructure, including in images you build for your clusters, without paying a license fee to the project. The supported version windows matter more for planning than the license does, because they set how long each major version receives fixes.
- Supported windows: Version 18 is supported until November 14, 2030, version 17 until November 8, 2029, version 16 until November 9, 2028, version 15 until November 11, 2027 and version 14 until November 12, 2026.
- Unsupported versions: Version 13 and earlier are no longer supported, so any cluster on those releases needs an upgrade plan.
- Release cadence: A new major version arrives about once a year, and minor releases at least once every three months, according to the versioning policy.
- Upgrade paths: Minor releases replace executables and restart, while major upgrades use dump and restore, pg_upgrade or logical replication.
- Commercial support: The license has no paid edition. Any vendor support or extended arrangement is a separate contract, so confirm its terms with that vendor.
Check the current versioning policy on the project site before fixing a target major version for your cluster.
PgBouncer is a lightweight connection pooler for PostgreSQL that sits between applications and the database. Because it is a separate project from the PostgreSQL core, its license and distribution terms have to be read in its own repository rather than inferred from PostgreSQL. Confirm the license identifier in the project's LICENSE file and the release notes for the version you plan to deploy, since those are the authoritative sources for redistribution.
- License file: Read the LICENSE file in the official repository and record the exact license name and version for your compliance file.
- Edition model: Confirm in the project documentation whether any paid edition or commercial add-on exists. Do not assume one exists or does not exist.
- Packaging: If you use operating system packages or container images, check the license metadata those packages carry, because distributors may add their own terms.
- Support source: Identify whether support comes from the project community, your operating system vendor, or a third party, and get that arrangement in writing.
- Version pinning: Record the release you approved so that later upgrades go through the same license review.
Before you standardize on PgBouncer, confirm the license and any support arrangement against the project's current documentation and your legal team's requirements.
Pgpool-II is a middleware project that provides connection pooling, read query distribution, failed server removal, a watchdog for coordinating instances and online recovery. Like PgBouncer, it is a separate codebase with its own license and release terms, so the reader should verify them directly in the project's files and documentation. Because Pgpool-II carries more functions than a pooler, its license review should cover every bundled component you actually deploy.
- License file: Read the license text in the official source tree and confirm the exact name and version that applies to the release you intend to run.
- Bundled components: Check whether any extensions, tools or documentation included in your package carry different terms.
- Edition model: Confirm in the project documentation and any vendor material whether a paid edition or commercial support tier exists before you assume either way.
- Redistribution: If you bake Pgpool-II into images or appliances for your own clusters, confirm that the license permits that use and that your notices are included.
- Upgrade review: Repeat the license check on every major release, since terms can change between versions.
Before approving Pgpool-II, confirm its license identifier, any edition distinctions and support options against the project documentation and your procurement records.
What drives the running cost of each pooling layer
Both poolers cost more to run than their license line suggests, because the money goes to people, application changes and upgrades rather than software. The cards below separate one-time work from recurring effort so you can ask each vendor or partner for the right items in a written scope.
Pooler and node infrastructure
PgBouncer is a single lightweight process, and its default memory need is about 2 kB per client connection, so it usually adds little hardware. Pgpool-II is heavier: it runs as its own service layer, and a highly available setup adds further Pgpool-II instances for the watchdog. Each extra node is recurring compute and monitoring. Ask for the node count, the placement of each pooler relative to the database cluster, and whether the pooler runs on VMs or Kubernetes.
Pool sizing and mode tuning
Choosing session, transaction or statement mode, and setting pool sizes against the PostgreSQL connection limit, is a one-time design task that is repeated whenever traffic patterns change. Engineers measure connection counts, wait times and server utilization, then adjust. Costs rise with the number of applications sharing one pooler and with uneven workloads. Ask who owns the tuning after go-live and what load test evidence is delivered with the configuration.
Application changes for transaction pooling
Transaction pooling is the mode that most often saves database connections, but it breaks session state. Code that relies on SET and RESET, LISTEN, or named PREPARE and DEALLOCATE must be found and reworked, and that effort is largely one-time. It recurs when new features are added to the application. Ask the partner to inventory these patterns in your codebase and to include regression tests for the pooled path in the scope.
Failover and watchdog operations
Pgpool-II covers pooling, read distribution, removal of failed servers and watchdog coordination in one product, so its cost is in running that behavior. Someone must understand how the watchdog elects an active instance, how failed nodes are detected and how online recovery is run. This is a recurring operating load for an on-call team, and incidents in this layer are harder to diagnose than in a pooler alone. Ask for runbooks, alert definitions and a drill of a node failure.
Major version upgrades
PostgreSQL supports each major version for 5 years after its initial release, so both layers must follow the database through upgrades. Minor updates replace executables and restart the service. Major upgrades use pg_upgrade, dump and restore, or logical replication, and each pooler configuration must be retested against the new server. Pgpool-II's extra behavior adds test cases. Ask for the upgrade method, the tested target versions and whether the pooler change is included in the same change window.
Support, retainers and ownership
Vendor support contracts and external retainers add recurring cost, but the amount depends on what you need covered. Most DeployOpen engagements are fixed-scope, with the build, tuning and documentation agreed in writing before work starts, and ongoing support, upgrades and testing available as retainers. Retainer cost follows the hours, response expectations and the number of layers covered. Ask what is handed over, who holds the runbooks and what the exit path looks like if you change poolers later.
Moving from PgBouncer to Pgpool-II, or back, without an outage
This sequence moves client traffic between the two pooling layers in stages, so each application is verified before the old component is removed. The PostgreSQL databases stay in place throughout, and the written scope fixes the order of work before any change begins.
Inventory session-dependent application behavior
Review every application and connection string that reaches the cluster, and list which ones use SET or RESET, LISTEN and NOTIFY, PREPARE and DEALLOCATE, temporary tables, advisory locks or other session state. The application owners and the DeployOpen engineer doing the review sign off on the list. Done means each application is tagged as safe for transaction pooling, safe only for session pooling, or needs code changes first.
Decide the target pooling mode
Choose session, transaction or statement mode for each application group, based on the inventory. The PgBouncer features page warns that transaction pooling breaks client expectations of the server by design, so any application on the list needs either a code change or a session-mode pool. Pgpool-II also brings read load balancing and watchdog failover, so confirm whether those features are needed before choosing the target. Done means a written decision record names the mode and the owner for each application group.
Stand up the new layer beside the old one
Deploy the target pooler on its own listener or host, pointed at the same PostgreSQL primary and standbys, without moving any client yet. Rebuild the pooler configuration, pool sizes, authentication settings and health checks for the new component, and wire failover integration and monitoring to it. Done means the new pooler accepts test connections, reports healthy backends, and appears in the monitoring dashboards with alerts defined.
Validate prepared statements and session state
Run the test suite for each application against the new pooler, and check prepared statement handling, session variables, transaction boundaries and any LISTEN or NOTIFY usage. Confirm that role and search path settings behave as expected under the chosen mode. Done means each application passes its test suite and the results are recorded in the change ticket, with any failures tracked as blockers.
Shift traffic in stages
Move one application group at a time by changing its connection endpoint, starting with the lowest-risk workload. Watch connection counts, error rates and latency after each move before proceeding. Keep the old pooler running so a group can be pointed back if a check fails. Done means every group runs on the new pooler for an agreed observation period, with the rollback path tested for each stage.
Retire the old component after verification
Once all traffic has moved and the observation period has closed, disable the old pooler, remove its configuration and update the runbooks, backup notes and monitoring. The PostgreSQL databases, roles and data are not touched in this step, because they transfer unchanged. Done means the old component no longer receives connections and the runbooks reference only the new layer.
Plan any PostgreSQL major upgrade as a separate step
If a major version change is also planned, logical replication works between different PostgreSQL major versions and allows a major upgrade with only several seconds of downtime, according to the PostgreSQL upgrading documentation. Schedule this as its own change with its own rollback plan, and confirm the exact cutover method in the written scope. Done means the upgrade has an agreed cutover runbook and a tested fallback, separate from the pooler move.
Where pooler implementation projects usually run long
Pooler projects rarely run long because of the pooler itself. They run long on application compatibility testing, pool sizing under real load, failover testing against the HA manager, and coordination with the teams that own the applications. The application compatibility work is the largest unknown in a PgBouncer rollout, because transaction pooling changes what a client can safely assume about its server session. Before any cutover, the team should check each application for session-level SET or RESET, LISTEN, and PREPARE or DEALLOCATE use, as the PgBouncer features page describes, and agree which pool mode each application will use.
Implementing PgBouncer is mostly configuration and monitoring: pool modes, pool sizes, and client limits set in its configuration, plus alerting on connection wait and pool saturation. Implementing Pgpool-II adds more moving parts. Teams must configure health checks so failed backends are removed, set up read load balancing rules that match how each application reads and writes, and deploy a watchdog so that multiple Pgpool-II instances coordinate and avoid a single point of failure. Each of those pieces needs its own failover test, and the watchdog settings must be verified against the actual network layout. Monitoring for both should cover pool utilization, server connection counts and failover events, so that a pooler problem is not mistaken for a database problem.
Before scoping either project, the reader must supply four inputs: an application inventory listing each client, its driver, and whether it uses session state, prepared statements or listeners; a profile of connection patterns, including peak concurrency and bursts; the HA design, including which component detects primary failure and how Pgpool-II or PgBouncer will sit beside it; and the maintenance window policy, which decides when pool configuration changes and failover tests can run. Confirm these with the application owners and your DBA team in writing. A fixed-scope plan is easier to agree once these inputs are documented, because the compatibility and failover tests are where most of the effort sits.
PgBouncer vs Pgpool-II: questions buyers ask before hiring help
Does PgBouncer give me failover on its own?
No. PgBouncer is a connection pooler and does not detect a failed primary or promote a standby. PostgreSQL itself does not provide the software to detect a primary failure and notify the standby, so automatic failover needs an external tool such as Patroni or CloudNativePG. In a typical design, the HA manager promotes a new primary and PgBouncer is pointed at the current leader, either through a host name that moves with the leader or by reconfiguration. Ask your team or your implementation partner to show exactly how the pooler learns about the new primary and how long client connections take to reconnect during a test failover.
Can Pgpool-II replace Patroni for failover?
It can cover part of the job, but it does not replace an HA manager for every case. Pgpool-II documents automatic removal of failed servers, a watchdog that coordinates multiple Pgpool-II instances, and online recovery of a node with one command. Patroni manages leader election and configuration through a distributed store such as etcd, Consul, ZooKeeper or Kubernetes. Before you drop one for the other, confirm how each handles split-brain protection, fencing of the old primary, and which PostgreSQL versions your cluster needs. Test both in a staging copy of your topology.
Does transaction pooling work with my ORM code?
It works for many applications, but only if the code avoids session state. The PgBouncer features page warns that transaction pooling breaks client expectations of the server by design, so applications must avoid features such as SET and RESET, LISTEN, and PREPARE and DEALLOCATE. Many ORMs and drivers issue prepared statements or session-level settings by default, so a pool in transaction mode can surface errors that never appeared in session mode. Audit the ORM configuration, run your integration tests through the pooler, and check any background jobs that depend on session settings.
What does the work need from our internal team?
At minimum, you need people who can own the PostgreSQL cluster, the HA manager and the pooler as one system. The team should understand connection limits on the server, how the pooler maps client connections to server connections, and how application frameworks use prepared statements and session state. Someone also needs to own backups, upgrades and monitoring, because a pooler change can affect failover behavior. If these skills are thin, plan for training or outside help before the cutover, not after an incident.
Can our team set this up without outside help?
Some teams can, especially if they already operate PostgreSQL replication and an HA manager. The question is whether they can run failover tests, handle a failed node at night and change the pooling mode without breaking applications. Ask who will perform the first failover drill, who holds the runbook, and how application teams will be told about session-state restrictions. If the answer to any of these is unclear, an outside engineer can help plan and test while your staff keep ownership.
What drives the effort and cost of this work?
The main drivers are the number of applications and connections, how much session state they rely on, the number of PostgreSQL nodes, whether failover is automated, and how much testing your change process requires. Costs fall into one-time work (design, pooler configuration, application changes, failover testing and documentation) and recurring work (patching, minor PostgreSQL updates, monitoring and drills). PostgreSQL minor releases come at least once every three months and do not change the storage format, but each one still needs a restart and a test. Ask your advisers to split their estimate into these buckets.
What should we ask for in a fixed-scope quote?
Ask for a written scope that names each system in the design (PostgreSQL nodes, HA manager, pooler, and any load balancing), the applications covered, the pooling mode per application, the failover tests included, and the documents you will receive, such as the runbook and configuration. Ask what is excluded, such as application code changes, upgrades or monitoring, and how changes to scope are priced. Confirm acceptance criteria in writing, including how failover tests are measured. DeployOpen agrees scope, deliverables and timelines in writing before work starts, and provides a quote from that written scope.
How do we test failover safely?
Test in a staging environment that matches production topology, with realistic connection counts and the same pooler mode. Confirm backups and a tested restore before any drill. Stop the primary in a controlled way, record how long clients take to reconnect, check that the old primary cannot accept writes after promotion, and confirm that pooled connections do not keep stale state. Repeat the test after each PostgreSQL minor update and each pooler configuration change. Schedule production drills with an agreed rollback plan and a named owner for each step.
How DeployOpen helps choose, implement and migrate the pooling layer
DeployOpen starts by confirming which connection pattern your applications actually need before recommending PgBouncer, Pgpool-II, or both. We then implement the chosen layer inside your own infrastructure, test it against your failover and application behavior, and document it for your operations team. Ongoing support is available as a retainer.
How we scope
- Engagements are fixed-scope, with deliverables and timelines agreed in writing before work starts.
- We review which applications use session state, SET, LISTEN or PREPARE statements before choosing a pooling mode.
- The written scope names the PostgreSQL versions, cluster topology and failover manager the pooling layer must work with.
How we build
- We deploy the pooler on your VMs or Kubernetes cluster, configured to point at your primary and standbys.
- We test pool sizing, pooling mode and client behavior under failover in a non-production environment first.
- Where read load balancing is in scope, we validate routing rules and node removal against your replication setup.
How we hand over
- You receive configuration, runbooks and documentation covering pooling mode, connection limits and failover steps.
- We walk your engineers through day-two tasks such as adding a node, changing a pool setting and reading the logs.
- Handover covers the application changes needed for transaction pooling, so your developers know which features to avoid.
How we support
- Post-handover support, upgrades and continuous testing are available as a retainer, scoped in writing.
- We can re-test the pooling layer after PostgreSQL minor or major upgrades within the agreed retainer scope.
- Ask us to confirm which pooler version and PostgreSQL release the supported configuration targets before you sign.

