PgBouncer, Pgpool-II and others: A proxy for PostgreSQL 🐘
Published on 2025-10-30
A PostgreSQL proxy or connection pooler is an intermediary application that sits between your client applications and one or more PostgreSQL servers. It speaks the PostgreSQL network protocol, which allows any standard client (for example, your web server or an application in Java/Python/Go) to connect to the proxy believing it is talking directly to a PostgreSQL server.
Unlike MySQL, where proxies are often used for read/write splitting (R/W split) or caching, in the PostgreSQL world the main task of a proxy is efficient connection management.
The problem: PostgreSQL’s “Process per Connection”
PostgreSQL historically uses a process-per-connection model, where each new client connection spawns a separate postgres process.
This is reliable but resource-intensive: each process consumes roughly 10–20 MB RAM, plus overhead from fork/exec.
If your application opens hundreds or thousands of short-lived connections (for example, microservices, FaaS, web apps), the DB server becomes overloaded:
CPU load from fork increases, memory is exhausted, connections get “stuck.”
The solution is connection pooling. This is what PgBouncer, Pgpool-II, Odyssey and their peers do.
How a PostgreSQL proxy works
In a basic configuration the pooler simply forwards requests from the client to the PostgreSQL server. But its key feature is connection multiplexing:
Accept — the client application connects to the pooler (e.g., PgBouncer).
Idle pool — the pooler maintains a ready pool of real connections to the PostgreSQL server (already authenticated).
Routing — when the client issues a request:
- the pooler takes a free connection from the pool;
- executes the client’s transaction;
- returns the connection back to the pool, resetting its state.
Response — the result is returned to the client.
Result: thousands of client “lightweight” connections are handled by dozens of “heavy” connections to the DB. Resource savings are an order of magnitude.
Main functions and responsibilities
| Category | Responsibilities | Example use cases |
|---|---|---|
| Optimization | Connection pooling (multiplexing) | Reducing load from thousands of clients |
| Scalability | Read/Write Split, load balancing | SELECT → replicas, INSERT/UPDATE → primary |
| Availability | Failover, server health monitoring | Automatic switchover on primary failure |
| Security | Authentication management, TLS termination | Centralized users, encryption |
Some proxies also support query caching, metrics collection and Prometheus exporters.
Types of PostgreSQL proxies
1. Lightweight connection poolers (Layer 7, not SQL-aware)
They understand the PostgreSQL protocol but do not parse SQL. The main goal is fast multiplexing with minimal latency (<1 ms).
| Pooler | Key features | Pooling modes | Read/Write Split | Failover | Active support |
|---|---|---|---|---|---|
| PgBouncer | Most popular. Lightweight (~5MB RAM), fast, stable. Supports pause/resume, online restart. | ✅ Session, Transaction, Statement | ❌ No | ❌ No | ✅ Yes |
| Odyssey | From Yandex, now open-source. Multithreaded (epoll), scales to 100k+ connections. | ✅ Session, Transaction | ❌ No | ❌ No (graceful shutdown) | ✅ Yes |
| PgCat | New (Rust, 2023+). High-performance, built-in metrics, shard support. | ✅ Transaction, Session | ✅ Basic | ❌ No | ✅ Yes |
Pooling modes:
- Session — the connection is held until disconnect (convenient but does not save resources).
- Transaction — the connection is given for the duration of a transaction (BEGIN…COMMIT). Optimal balance.
- Statement — the connection is used for a single statement (maximum savings, but strict limitations).
2. SQL-aware proxies (they parse SQL)
They inspect SQL traffic, enabling R/W split, caching and query analysis.
| Proxy | Key features | Pooling | Read/Write Split | Failover (HA) | Sharding | Support |
|---|---|---|---|---|---|---|
| Pgpool-II | “All-in-one”: pooling, R/W split, query cache, watchdog for HA. | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes |
| Heimdall Data | Cloud proxy with caching and auto R/W split. | ✅ Yes | ✅ Yes (advanced) | ✅ Yes | ❌ No | ✅ Yes (commercial) |
| Citus (Coordinator) | Extension for horizontal sharding. | ❌ No (internal) | ✅ Yes (internal) | ✅ Yes (internal) | ✅ Yes | ✅ Yes |
3. TCP/Layer 4 proxies (do not understand the protocol)
| Proxy | Description | Limitations |
|---|---|---|
| HAProxy | High-performance TCP/HTTP load balancer. Can check PostgreSQL health. | Cannot do R/W split without external hints |
| Keepalived | Manages a VIP for HA. Used together with PgBouncer/Pgpool. | No SQL intelligence |
| Envoy | Modern service mesh proxy with experimental Postgres protocol support. | High complexity and overhead |
Configuration examples
PgBouncer (transaction pooling)
[databases]
my_app_db = host=127.0.0.1 port=5432 dbname=real_db_name
[pgbouncer]
listen_port = 6432
listen_addr = *
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction ; Рекомендуемый режим
max_client_conn = 2000
default_pool_size = 20 ; Подбирайте под RAM/CPU (~10–50 на ядро)
reserve_pool_size = 5
Pgpool-II (R/W split and HA)
listen_addresses = '*'
port = 9999
enable_pooling = on
num_init_children = 32
max_pool = 4
backend_hostname0 = 'primary_host'
backend_port0 = 5432
backend_weight0 = 1.0
backend_hostname1 = 'replica_host'
backend_port1 = 5432
backend_weight1 = 1.0
load_balance_mode = on
primary_node_id = 0
watchdog_enable = on
Odyssey (multithreaded YAML config)
daemonize: false
pid_file_path: /tmp/odyssey.pid
listeners:
- host: 0.0.0.0
port: 6432
database: my_app_db
users:
- name: app_user
password: secret
pool_size: 20
pool_mode: transaction
storage:
- name: postgres
type: remote
hosts:
- host: 127.0.0.1
port: 5432
How to choose a tool
| Task | Recommendation | Why |
|---|---|---|
| Just reduce connection load | PgBouncer | Lightweight, fast, industry standard |
| R/W split + HA in one solution | Pgpool-II | All-in-one: pooling, balancing, cache |
| Scale to 100k+ connections | Odyssey or PgCat | Multithreading and high performance |
| Horizontal sharding | Citus | Distributed PostgreSQL |
| Cloud-native infrastructure | Cloud SQL Proxy or ProxySQL | Integration with IAM and auto-scaling |
| Simple TCP load balancing | HAProxy + Patroni | Reliable master failover |
Best Practices
- Monitoring: use
SHOW STATS;(PgBouncer) or Prometheus exporters. - Pool size:
default_pool_size = (RAM / 20MB) / databases, but no more than 100–200 per server. - Security: enable
sslmode=requireand terminate TLS at the pooler. - Load: test with
pgbench, aiming for <5 ms latency. - Kubernetes: deploy PgBouncer as a sidecar, HAProxy as a DaemonSet.
Conclusion
In the PostgreSQL ecosystem a connection pooler is not an option but a necessity for any high-load system (100+ RPS).
- Start with PgBouncer — it solves 90% of connection problems.
- Use Pgpool-II if you need built-in R/W split and query cache.
- Use Odyssey or PgCat for modern large-scale setups.
- Add HAProxy + Patroni if HA and replication at the TCP level are required.
With the right proxy your PostgreSQL will handle thousands of clients and remain calm as an elephant 🐘.
Related reviews
Mikhail helped set up the website very quickly. I would’ve definitely been fiddling with it all day. It’s great when a professional saves your time and delivers high-quality work. I recommend him!
N_Konstantin · VPS setup, server setup
An established customer2025-10-21 · ⭐ 5/5
Mikhail was very prompt in helping set up the website. I would definitely have been tinkering with it all day. It's nice when a professional helps save your time and does the work at a high level. I recommend him!
The most qualified, top-notch specialist who knows his stuff.
Alexeyvodopyanov · VPS setup, server setup
Experienced buyer2025-10-21 · ⭐ 5/5
The most qualified and coolest specialist who knows their stuff
Everything is fast and high-quality
Alexeyvodopyanov · VPS setup, server setup
Experienced buyer2025-10-16 · ⭐ 5/5
Everything fast and high-quality
The task was completed in 30 minutes! I recommend!
fedinseo · VPS setup, server setup
A very powerful buyer2025-10-15 · ⭐ 5/5
The task was completed in 30 minutes! I recommend it!
Mikhail is an outstanding professional! You can tell he has a great deal of experience. The work was done precisely and on time. We had to tinker a bit because the project installed on the server wasn't perfect, but Mikhail carefully and thoughtfully guided us on what to do and how. In the end, everything worked! I recommend him to anyone who values quality.
N_Konstantin · VPS setup, server setup
A settled customer2025-10-10 · ⭐ 5/5
Mikhail is an excellent performer! You can tell he has a wealth of experience. The work was done precisely and on time. We had to tinker due to imperfections in the project that was being installed on the server, but Mikhail carefully and thoughtfully advised what to do and how to do it. In the end, everything worked! I recommend him to anyone for whom the quality of work is important!
Everything's great, as always! Fast, clear and to the point. Thanks!
Dina_Perova · VPS setup, server configuration
Established customer2025-09-18 · ⭐ 5/5
Everything's great, as always! Fast, clear and to the point. Thank you!