docker.recipes

PgBouncer Connection Pooling

intermediate

Lightweight PostgreSQL connection pooler for high-performance applications.

Overview

PgBouncer is a lightweight connection pooler for PostgreSQL developed to address connection overhead and resource exhaustion in high-concurrency applications. Unlike direct database connections that consume significant memory and processing power per connection, PgBouncer maintains a small pool of persistent connections to PostgreSQL while serving hundreds or thousands of client connections efficiently. This middleware layer dramatically reduces connection establishment overhead and prevents PostgreSQL from being overwhelmed by connection storms. This stack combines PgBouncer with PostgreSQL 16 and pgAdmin to create a complete database solution with built-in connection pooling. The configuration uses transaction-level pooling, where connections are returned to the pool after each transaction completes, maximizing connection reuse while maintaining transaction isolation. Applications connect to PgBouncer on port 6432, which intelligently routes queries through a managed pool of 20 connections to the underlying PostgreSQL instance. High-traffic applications, SaaS platforms, and microservices architectures benefit most from this setup. Organizations experiencing PostgreSQL connection limits, slow application response times due to connection overhead, or seeking to optimize database resource utilization will find immediate value. The transaction pooling mode makes this particularly effective for web applications with short-lived queries, API backends serving multiple clients simultaneously, and environments where connection counts significantly exceed optimal database connection limits.

Key Features

  • Transaction-level connection pooling with configurable pool sizes (20 default, 5 minimum, 5 reserve)
  • Support for up to 1,000 concurrent client connections through intelligent connection multiplexing
  • PostgreSQL 16 with Alpine Linux base for enhanced performance and security features
  • pgAdmin 4 web interface for visual connection pool monitoring and database administration
  • Health check integration ensuring PgBouncer only starts after PostgreSQL is ready
  • Automatic connection recycling and idle connection management
  • SQL query routing and protocol translation between clients and PostgreSQL
  • Real-time connection statistics and pool utilization metrics through pgAdmin

Common Use Cases

  • 1Web applications with hundreds of concurrent users experiencing PostgreSQL max_connections limits
  • 2Microservices architectures where multiple services need database access without connection proliferation
  • 3SaaS platforms serving multiple tenants requiring efficient database resource sharing
  • 4API backends with burst traffic patterns that overwhelm direct PostgreSQL connections
  • 5Development environments needing production-like connection pooling for realistic testing
  • 6Legacy applications that create excessive database connections without connection management
  • 7High-frequency trading or analytics applications requiring minimal connection establishment latency

Prerequisites

  • Minimum 1.5GB RAM (512MB PostgreSQL + 256MB pgAdmin + 128MB PgBouncer + overhead)
  • Docker Engine 20.10+ with Docker Compose v2 support
  • Available ports 5432 (PostgreSQL), 6432 (PgBouncer), and 8080 (pgAdmin)
  • Understanding of PostgreSQL connection limits and pooling concepts
  • Basic knowledge of environment variable configuration for database credentials
  • Familiarity with transaction vs session vs statement pooling modes

For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms

docker-compose.yml

docker-compose.yml
1services:
2 pgbouncer:
3 image: edoburu/pgbouncer:latest
4 ports:
5 - "6432:6432"
6 environment:
7 DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
8 POOL_MODE: transaction
9 MAX_CLIENT_CONN: 1000
10 DEFAULT_POOL_SIZE: 20
11 MIN_POOL_SIZE: 5
12 RESERVE_POOL_SIZE: 5
13 depends_on:
14 postgres:
15 condition: service_healthy
16 networks:
17 - pg-net
18 restart: unless-stopped
19
20 postgres:
21 image: postgres:16-alpine
22 ports:
23 - "5432:5432"
24 environment:
25 POSTGRES_USER: ${POSTGRES_USER}
26 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
27 POSTGRES_DB: ${POSTGRES_DB}
28 volumes:
29 - postgres_data:/var/lib/postgresql/data
30 healthcheck:
31 test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
32 interval: 10s
33 timeout: 5s
34 retries: 5
35 networks:
36 - pg-net
37 restart: unless-stopped
38
39 pgadmin:
40 image: dpage/pgadmin4:latest
41 ports:
42 - "8080:80"
43 environment:
44 PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL}
45 PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD}
46 volumes:
47 - pgadmin_data:/var/lib/pgadmin
48 depends_on:
49 - postgres
50 networks:
51 - pg-net
52 restart: unless-stopped
53
54volumes:
55 postgres_data:
56 pgadmin_data:
57
58networks:
59 pg-net:
60 driver: bridge

.env Template

.env
1# PostgreSQL
2POSTGRES_USER=app
3POSTGRES_PASSWORD=secure_postgres_password
4POSTGRES_DB=app
5
6# PgAdmin
7PGADMIN_EMAIL=admin@example.com
8PGADMIN_PASSWORD=secure_pgadmin_password

Usage Notes

  1. 1Connect applications to PgBouncer at localhost:6432
  2. 2Direct PostgreSQL at localhost:5432
  3. 3PgAdmin at http://localhost:8080
  4. 4Transaction pooling mode for optimal performance

Individual Services(3 services)

Copy individual services to mix and match with your existing compose files.

pgbouncer
pgbouncer:
  image: edoburu/pgbouncer:latest
  ports:
    - "6432:6432"
  environment:
    DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
    POOL_MODE: transaction
    MAX_CLIENT_CONN: 1000
    DEFAULT_POOL_SIZE: 20
    MIN_POOL_SIZE: 5
    RESERVE_POOL_SIZE: 5
  depends_on:
    postgres:
      condition: service_healthy
  networks:
    - pg-net
  restart: unless-stopped
postgres
postgres:
  image: postgres:16-alpine
  ports:
    - "5432:5432"
  environment:
    POSTGRES_USER: ${POSTGRES_USER}
    POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    POSTGRES_DB: ${POSTGRES_DB}
  volumes:
    - postgres_data:/var/lib/postgresql/data
  healthcheck:
    test:
      - CMD-SHELL
      - pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}
    interval: 10s
    timeout: 5s
    retries: 5
  networks:
    - pg-net
  restart: unless-stopped
pgadmin
pgadmin:
  image: dpage/pgadmin4:latest
  ports:
    - "8080:80"
  environment:
    PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL}
    PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD}
  volumes:
    - pgadmin_data:/var/lib/pgadmin
  depends_on:
    - postgres
  networks:
    - pg-net
  restart: unless-stopped

Quick Start

terminal
1# 1. Create the compose file
2cat > docker-compose.yml << 'EOF'
3services:
4 pgbouncer:
5 image: edoburu/pgbouncer:latest
6 ports:
7 - "6432:6432"
8 environment:
9 DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
10 POOL_MODE: transaction
11 MAX_CLIENT_CONN: 1000
12 DEFAULT_POOL_SIZE: 20
13 MIN_POOL_SIZE: 5
14 RESERVE_POOL_SIZE: 5
15 depends_on:
16 postgres:
17 condition: service_healthy
18 networks:
19 - pg-net
20 restart: unless-stopped
21
22 postgres:
23 image: postgres:16-alpine
24 ports:
25 - "5432:5432"
26 environment:
27 POSTGRES_USER: ${POSTGRES_USER}
28 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
29 POSTGRES_DB: ${POSTGRES_DB}
30 volumes:
31 - postgres_data:/var/lib/postgresql/data
32 healthcheck:
33 test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
34 interval: 10s
35 timeout: 5s
36 retries: 5
37 networks:
38 - pg-net
39 restart: unless-stopped
40
41 pgadmin:
42 image: dpage/pgadmin4:latest
43 ports:
44 - "8080:80"
45 environment:
46 PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL}
47 PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD}
48 volumes:
49 - pgadmin_data:/var/lib/pgadmin
50 depends_on:
51 - postgres
52 networks:
53 - pg-net
54 restart: unless-stopped
55
56volumes:
57 postgres_data:
58 pgadmin_data:
59
60networks:
61 pg-net:
62 driver: bridge
63EOF
64
65# 2. Create the .env file
66cat > .env << 'EOF'
67# PostgreSQL
68POSTGRES_USER=app
69POSTGRES_PASSWORD=secure_postgres_password
70POSTGRES_DB=app
71
72# PgAdmin
73PGADMIN_EMAIL=admin@example.com
74PGADMIN_PASSWORD=secure_pgadmin_password
75EOF
76
77# 3. Start the services
78docker compose up -d
79
80# 4. View logs
81docker compose logs -f

One-Liner

Run this command to download and set up the recipe in one step:

terminal
1curl -fsSL https://docker.recipes/api/recipes/pgbouncer-pool/run | bash

Troubleshooting

  • PgBouncer connection refused: Verify PostgreSQL health check passes before PgBouncer starts using docker-compose logs postgres
  • Application timeout errors: Increase DEFAULT_POOL_SIZE or check for long-running transactions blocking pool connections
  • pgAdmin cannot connect to database: Use postgres:5432 as hostname, not localhost, when configuring server connections
  • Pool exhaustion warnings: Monitor connection usage patterns and adjust MAX_CLIENT_CONN or pool size parameters
  • Authentication failed through PgBouncer: Ensure DATABASE_URL credentials match PostgreSQL POSTGRES_USER and POSTGRES_PASSWORD exactly
  • High connection latency: Switch to session pooling mode if application maintains transaction state across requests

Community Notes

Loading...
Loading notes...

Download Recipe Kit

Get all files in a ready-to-deploy package

Includes docker-compose.yml, .env template, README, and license

Ad Space