Solution:
Root Cause: Excessive Direct Client Connections Spawning Dedicated OS Processes PostgreSQL uses a process-per-connection architecture. Each incoming client connection forks a dedicated backend process, consuming memory (
work_mem,
shared_buffers context, stack size) and incurring heavy CPU context switching overhead. When application instances scale horizontally or launch unpooled microservices, the connection count rapidly hits the configured
max_connections limit, resulting in
FATAL: sorry, too many clients already.
Step-by-Step Fix: 1 Audit Current Connection Counts via SQL:
Connect to PostgreSQL as superuser and execute: Copy
sql
SELECT count(*), state, usename, client_addr
FROM pg_stat_activity
GROUP BY state, usename, client_addr
ORDER BY count(*) DESC;
2 Install and Configure PgBouncer:
Install PgBouncer package on Linux: Copy
bash
sudo apt-get install pgbouncer # Ubuntu/Debian
sudo yum install pgbouncer # RHEL/CentOS
Edit /etc/pgbouncer/pgbouncer.ini to enable transaction pooling: Copy
ini
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb
[pgbouncer]
listen_port = 6432
listen_addr = *
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 5000
default_pool_size = 20
min_pool_size = 10
reserve_pool_size = 5
3 Tune postgresql.conf Settings:
Set max_connections to a safe limit based on available hardware (e.g., 100–200 max connections) in /etc/postgresql/16/main/postgresql.conf: Copy
ini
max_connections = 100
4 Restart Services and Redirect Application Traffic:
Reload PostgreSQL: sudo systemctl reload postgresql Start PgBouncer: sudo systemctl restart pgbouncer Point application connection strings to PgBouncer port 6432.