PgBouncer on a VPS: PostgreSQL Connection Pooling Setup and Sizing

PostgreSQL is memory-hungry per connection: each idle client connection can consume several megabytes of RAM, and on a small VPS with 2–4 GB of RAM, an application that opens hundreds of connections can exhaust memory before the database even does any real work. PgBouncer fixes that by sitting between your application and PostgreSQL and multiplexing many client connections onto a small pool of server connections. This guide covers installation, configuration, pool sizing, and the pitfalls to avoid.

Do you actually need a pooler?

You need PgBouncer if your application opens many short-lived connections — typical for server-side frameworks, web apps with per-request connections, or ORMs that do not reuse connections well. You may not need it if your app uses a single long-lived connection pool that is already sized to your RAM. A quick check: count connections with SELECT count(*) FROM pg_stat_activity; and compare against your VPS memory.

Installing PgBouncer

PgBouncer is in the standard repositories of every major distribution:

  • Debian/Ubuntu: apt install pgbouncer
  • RHEL/AlmaLinux: dnf install pgbouncer

Configuration lives in /etc/pgbouncer/pgbouncer.ini, with authentication in /etc/pgbouncer/userlist.txt.

Configuring pgbouncer.ini

A minimal working configuration looks like this:

[databases]
mydb = host=/var/run/postgresql port=5432 dbname=mydb

[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 20

  • listen_addr = 127.0.0.1 — bind to localhost so clients reach PgBouncer through the same host; never expose 6432 publicly
  • pool_mode = transaction — the right default for web workloads; connections are recycled after each transaction
  • max_client_conn — the maximum number of client connections PgBouncer will accept
  • default_pool_size — server connections kept open per database, sized to your CPU and RAM

Setting up the auth file

Create userlist.txt with the database users PgBouncer may authenticate. Passwords must be MD5 hashes in the format PostgreSQL uses:

"myapp" "md5" + md5(password + username)

You can generate the hash with SELECT md5('password' || 'myapp'); in psql, or copy the value of rolpassword from pg_authid if you have access. Then restart PgBouncer: systemctl restart pgbouncer.

Pool modes: transaction vs session

The pool_mode setting changes how aggressively connections are recycled. transaction mode returns a server connection to the pool as soon as the current transaction finishes, which means 100 concurrent clients can share as few as 10–20 server connections. session mode keeps the association for the entire client session — closer to what a single long-lived connection looks like, but it needs more server connections.

Use transaction mode for web applications and APIs: it gives the biggest memory savings. Use session mode only for clients that rely on session-scoped state such as SET statements, temporary tables, or advisory locks held across transactions.

Securing the connection

PgBouncer should never be exposed to the public internet. Bind it to 127.0.0.1 and let your application connect over localhost, or put it behind a firewall if your application runs on another host. For remote clients, add TLS on top:

  • client_tls_sslmode = require — encrypt client-to-PgBouncer traffic
  • server_tls_sslmode = require — encrypt PgBouncer-to-PostgreSQL traffic
  • Point client_tls_cert_file and client_tls_key_file at a certificate for your hostname

Keep auth_type at md5 or scram-sha-256 rather than trust, even on localhost — a misconfigured application should not get in without credentials.

Sizing the pools for your VPS

The two numbers that matter are default_pool_size and max_client_conn. A good starting point on a 2 vCPU / 4 GB VPS:

SettingValueRationale
default_pool_size10–20Each server connection costs RAM; 20 connections is plenty for most web apps on 4 GB
max_client_conn500–1000Clients are cheap (they only queue); cap them to avoid runaway apps
reserve_pool_size5Kept free for admin queries so the app cannot starve you out
server_idle_timeout300Close idle server connections to free memory

Monitor with SHOW POOLS; and SHOW STATS; from psql -p 6432 pgbouncer. If maxwait climbs, your pool is too small; if server connections sit idle, shrink it.

Pointing your application at PgBouncer

Change the application’s database host and port to 127.0.0.1:6432 and keep the same database name and credentials. Keep one direct connection to PostgreSQL on port 5432 for administrative work such as migrations, and be careful with features PgBouncer does not handle well:

  • Prepared statements in transaction mode can break; enable server_prepare_mode or use the session pool for those clients
  • Features like LISTEN/NOTIFY and advisory locks behave differently across pooled connections
  • Long-running reporting queries will hold a server connection; route them through a separate pool or database entry

Monitoring and common mistakes

  • Watch memory: if PostgreSQL still uses too much RAM, reduce shared_buffers and work_mem before growing the pool
  • Set statement_timeout in PostgreSQL so one slow query cannot hog a pooled connection
  • Do not expose port 6432 publicly; PgBouncer is not a security boundary
  • Test failover: if PostgreSQL restarts, PgBouncer should reconnect automatically

PgBouncer removes one of the most common memory ceilings on small database servers. If you are still deciding where to host that database, see the full VPS comparison on our table to compare plans with enough RAM headroom, and browse our provider breakdowns and buying guides on the main site for PostgreSQL tuning guides that complement this setup.

Looking for a place to run these setups? InterServer VPS plans offer straightforward pricing with plenty of headroom, and Cloudways managed cloud hosting is a solid choice if you prefer a managed platform on top of fast infrastructure. (Disclosure: we may earn a commission if you sign up through these links, at no extra cost to you.)

Leave a Reply