PgBouncer
PgBouncer is a lightweight connection pooler for PostgreSQL. As a pgcli addon it runs as a container in front of one or more PostgreSQL instances, reusing server connections across many short-lived client sessions — transaction-level pooling by default.
PgBouncer supports two deployment modes:
- Local:
pg addon install pgbouncer -i <instance>— stored underinstances.<name>.addons - Remote:
pg addon install pgbouncer --dsn <dsn> --pg-name <name>— stored in top-leveladdons.pgbouncer
Platform support
PgBouncer works on Linux (host networking, including cross-host pools) and
on macOS for single-host dev/test (the container joins the pgcli-net
bridge and publishes its port, the same way a PG instance does under podman
machine). On macOS:
- Local mode just works: PgBouncer reaches the managed instance by its container name automatically — no address to configure.
- Remote mode: the
--dsnhost must be reachable from the Mac — do not point it at127.0.0.1, which is the Mac itself, not the podman machine VM. - Client connections still target
127.0.0.1:<port>; gvproxy forwards the published port to the Mac’s loopback, exactly as for a PG instance.
How It Works
pg addon install pgbouncergenerates configuration files and starts the container- Config files live in
<base-dir>/addon/pgbouncer/<instance>/ - The container reaches PostgreSQL over the host network (Linux) or the
pgcli-netbridge by container name (macOS) - Config file updates restart the container automatically
Namespace isolation: PgBouncer respects the config’s namespace setting.
Container names and auth users include the namespace prefix (e.g.
pgb_<namespace>_<instance>), so different configs with different namespaces
can create independent poolers for the same PostgreSQL instance without
conflicting.
Commands
Install
Parameters:
| Parameter | Description | Default |
|---|---|---|
--dsn |
PG instance connection string (remote mode) | — |
--pg-name |
Name to identify a remote PgBouncer (required with –dsn) | — |
--max-client-conn |
Maximum client connections | 100 |
--default-pool-size |
Default pool size | 20 |
--min-pool-size |
Minimum pool size (warmup) | 0 |
--reserve-pool-size |
Reserve pool size (burst) | 0 |
--max-db-connections |
Max connections per database | 50 |
--max-user-connections |
Max connections per user | 0 (unlimited) |
--server-idle-timeout |
Idle server connection timeout (seconds) | 600 |
--server-lifetime |
Max server connection lifetime (seconds) | 3600 |
--server-connect-timeout |
PostgreSQL connection timeout (seconds) | 15 |
--query-timeout |
Query timeout (seconds) | 0 (unlimited) |
--query-wait-timeout |
Wait for connection timeout (seconds) | 120 |
--idle-transaction-timeout |
Idle transaction timeout (seconds) | 0 |
--transaction-timeout |
Transaction timeout (seconds) | 0 |
--admin-users |
Admin users list | (empty) |
--stats-users |
Read-only stats users list | (empty) |
--log-connections |
Log connections | 0 |
--log-disconnections |
Log disconnections | 0 |
List
PgBouncer appears under Local add-ons / Remote add-ons:
Start and stop
After a reboot or manual stop, bring the pooler back up without re-running install (config and auth users are untouched):
start is idempotent — a running pooler is left alone. stop keeps the
container and its config; use pg addon remove to tear it down.
Remove
Workflow:
- Stop and remove the addon container
- Delete the
<base-dir>/addon/pgbouncer/<instance>/directory and files - Remove the addon entry from
pg.yaml
Configuration
Local mode (under instances.<name>.addons):
Remote mode (under top-level addons):
Generated files, per instance, under <base-dir>/addon/pgbouncer/:
Authentication
PgBouncer uses the auth_query method for dynamic password lookup:
- A per-pooler auth user is created on PostgreSQL with a random password, named
pgb_<namespace>_<instance>(e.g.pgb_default_mypg,pgb_test-ns_my-remote) - A shared
SECURITY DEFINERfunctionpgbouncer_lookup()is installed to querypg_authid - When a client connects, PgBouncer uses its own auth user to run the auth_query and fetch the real user’s password hash
- The password is cached in PgBouncer’s memory for subsequent connections
userlist.txt only contains the pooler’s auth user (plaintext password). All other users are authenticated dynamically via auth_query — no password sync needed.
Each pooler gets its own PG auth user, so multiple poolers (local or cross-host) targeting the same PG instance do not conflict.
After changing a PostgreSQL user’s password, re-run pg addon install pgbouncer to reset the auth cache, or connect to the admin console and run RECONNECT.
Connecting
Clients connect through the addon port:
Port allocation: PgBouncer defaults to port 56432; if occupied, pgcli
assigns the next free port. View the current port with pg addon list.
Use Cases
High Concurrency
Short-Lived Connections
Long-Lived Connections
Read Replicas
Monitoring
PgBouncer exposes an admin console for pool and runtime status.
Connecting to the Admin Console
Connect to the pgbouncer virtual database as an admin user:
Example:
Note: Only users listed in admin_users can access the admin console.
Common SHOW Commands
| Command | Description |
|---|---|
SHOW pools |
Connection pool status (active/waiting client and server connections) |
SHOW clients |
All current client connections with details |
SHOW servers |
All current server (PostgreSQL) connections with details |
SHOW databases |
Configured databases and their connection parameters |
SHOW stats |
Traffic statistics (transactions, queries, bytes received/sent) |
SHOW config |
All runtime configuration parameters |
SHOW sockets |
Low-level TCP socket information |
SHOW active_sockets |
Active TCP sockets |
SHOW mem |
Memory usage statistics |
SHOW lists |
Summary of various object counts |
Examples
Other Admin Commands
| Command | Description |
|---|---|
RELOAD |
Reload configuration file |
PAUSE |
Pause connection pool (wait for transactions to complete) |
RESUME |
Resume connection pool |
RECONNECT |
Force reconnect all server connections |
SHUTDOWN |
Shutdown PgBouncer |
Troubleshooting
Connection Pool Full
Cause: Reached max_client_conn limit.
Authentication Failure
Cause: Auth cache contains a stale password hash.
Container Won’t Start
Common causes: config syntax error, malformed user list, or port already in use.
Query Timeout
Cause: Query exceeded query_timeout.
Notes
- Port: PgBouncer defaults to 56432; ensure firewall rules allow access
- Passwords: After changing a PostgreSQL user password, re-run
pg addon installto reset the auth cache - Config edits: After editing config files manually, restart to apply:
- Transaction mode:
transactionmode does not support session-level features (e.g. temporary tables); usesessionmode instead