Troubleshooting & Comparisons

Postgres Too Many Connections: Pooling with PgBouncer

Learn to resolve PostgreSQL's "too many connections" issue with PgBouncer, optimizing performance and handling high concurrency setups effectively.

4 min read

Learn how to troubleshoot and resolve the "too many connections" error in PostgreSQL using PgBouncer, a lightweight connection pooler designed for high-concurrency setups.

Symptom: "Too Many Connections" Error in PostgreSQL

The "too many connections" error occurs in PostgreSQL when the number of concurrent client connections exceeds the max_connections limit set in the database server. Causes include:

  • PostgreSQL allocates a process for each database client connection, consuming significant system resources.
  • Applications with high concurrency demands, such as web services, can quickly exhaust connection allowances, particularly during peak traffic periods.
  • The error can lead to system downtime or degraded application performance.

Understanding the Cause: Connection Limitation Mechanisms

PostgreSQL's connection model creates a new backend process for each client. Here's why this can be problematic:

  1. Resource Costs: Each backend process involves memory allocation, file descriptors, and initialization overhead.
  2. High Overhead for Short-lived Connections: Many applications make short-lived connections, magnifying these resource costs under high workloads.
  3. Scalability Limits: As max_connections increases, contention for resources such as CPU and memory can arise, causing overall database performance to degrade.

PgBouncer addresses these issues by pooling database connections and acting as a lightweight intermediary between clients and the database.

Fix: Implementing PgBouncer as a Connection Pooler

PgBouncer reduces connection-management overhead by creating a connection pool, keeping active connections open for reuse. Follow these steps to implement PgBouncer:

prerequisites

  • PostgreSQL installed and running.
  • Superuser access to the PostgreSQL database.
  • Operating system package manager (e.g., apt, yum, brew) or the ability to compile from source.

steps

  1. Install PgBouncer

    bash
    # On Ubuntu/Debian
    sudo apt install pgbouncer
    
    # On CentOS/RedHat
    sudo yum install pgbouncer
    
    # On macOS using Homebrew
    brew install pgbouncer
  2. Create a PostgreSQL User for Authentication Connect to your database and create a user for PgBouncer to use.

    sql
    CREATE USER pgbouncer_user WITH PASSWORD 'your_password';
  3. Configure pgbouncer.ini Locate the default configuration file and modify it to include a specific database setup:

    bash
    nano /etc/pgbouncer/pgbouncer.ini

    Update the [databases] section:

    [databases]
    test_db = host=127.0.0.1 port=5432 dbname=test_db user=pgbouncer_user password=your_password
  4. Optimize Pooling Settings Add or adjust parameters for PgBouncer, like min_pool_size, default_pool_size, and max_client_conn:

    min_pool_size = 10
    default_pool_size = 20
    max_client_conn = 100
  5. Start PgBouncer

    bash
    sudo systemctl start pgbouncer
  6. Connect Through PgBouncer Update your application's database settings to point to the PgBouncer port (default is 6432).

    bash
    psql -h 127.0.0.1 -p 6432 -U pgbouncer_user -d test_db

Common Configuration Pitfalls and Verification Steps

After configuring, verify that PgBouncer is working using the SHOW POOLS; SQL statement in the psql client—this displays real connection pool statistics.

Selecting Connection Pooling Modes

PgBouncer offers three pooling modes, each suited for specific use cases:

Choose the Right Pooling Mode

  • Use Session mode for transaction-heavy applications that require longer-lived connections.
  • Use Transaction mode for high concurrency, but beware: this mode resets the connection state after each transaction and may break functionality requiring persistent connections (e.g., prepared statements).
  • Use Statement mode for applications relying on small, stateless queries, but note it restricts functionality like multi-statement transactions.

Testing Performance Improvement with pgBench

Benchmark the effectiveness of PgBouncer under load using pgBench:

bash
# Base PostgreSQL benchmark
pgbench -c 20 -T 30 -h 127.0.0.1 -p 5432 -U postgres test_db

# Benchmark with PgBouncer
pgbench -c 20 -T 30 -h 127.0.0.1 -p 6432 -U postgres test_db

You should observe significant performance improvements with PgBouncer, including reduced connection setup overhead and increased handling capacity.

FAQ

Why does PostgreSQL have a default connection limit?

PostgreSQL uses a process-per-connection model. The max_connections limit prevents resource exhaustion that could crash the database server.

How does PgBouncer differ from increasing max_connections?

Increasing max_connections allows more simultaneous connections but also increases resource usage per connection. PgBouncer, on the other hand, reuses open connections, improving resource efficiency without additional system overhead.

Can PgBouncer replace PostgreSQL high-availability setups?

No, PgBouncer is a connection pooler. For high-availability clusters, you need additional tools like Pgpool-II or HAProxy along with replication configurations.


Official reference: PgBouncer documentation.