PgBouncer Connection Pooling
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:latest4 ports: 5 - "6432:6432"6 environment: 7 DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}8 POOL_MODE: transaction9 MAX_CLIENT_CONN: 100010 DEFAULT_POOL_SIZE: 2011 MIN_POOL_SIZE: 512 RESERVE_POOL_SIZE: 513 depends_on: 14 postgres: 15 condition: service_healthy16 networks: 17 - pg-net18 restart: unless-stopped1920 postgres: 21 image: postgres:16-alpine22 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/data30 healthcheck: 31 test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]32 interval: 10s33 timeout: 5s34 retries: 535 networks: 36 - pg-net37 restart: unless-stopped3839 pgadmin: 40 image: dpage/pgadmin4:latest41 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/pgadmin48 depends_on: 49 - postgres50 networks: 51 - pg-net52 restart: unless-stopped5354volumes: 55 postgres_data: 56 pgadmin_data: 5758networks: 59 pg-net: 60 driver: bridge.env Template
.env
1# PostgreSQL2POSTGRES_USER=app3POSTGRES_PASSWORD=secure_postgres_password4POSTGRES_DB=app56# PgAdmin7PGADMIN_EMAIL=admin@example.com8PGADMIN_PASSWORD=secure_pgadmin_passwordUsage Notes
- 1Connect applications to PgBouncer at localhost:6432
- 2Direct PostgreSQL at localhost:5432
- 3PgAdmin at http://localhost:8080
- 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 file2cat > docker-compose.yml << 'EOF'3services:4 pgbouncer:5 image: edoburu/pgbouncer:latest6 ports:7 - "6432:6432"8 environment:9 DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}10 POOL_MODE: transaction11 MAX_CLIENT_CONN: 100012 DEFAULT_POOL_SIZE: 2013 MIN_POOL_SIZE: 514 RESERVE_POOL_SIZE: 515 depends_on:16 postgres:17 condition: service_healthy18 networks:19 - pg-net20 restart: unless-stopped2122 postgres:23 image: postgres:16-alpine24 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/data32 healthcheck:33 test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]34 interval: 10s35 timeout: 5s36 retries: 537 networks:38 - pg-net39 restart: unless-stopped4041 pgadmin:42 image: dpage/pgadmin4:latest43 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/pgadmin50 depends_on:51 - postgres52 networks:53 - pg-net54 restart: unless-stopped5556volumes:57 postgres_data:58 pgadmin_data:5960networks:61 pg-net:62 driver: bridge63EOF6465# 2. Create the .env file66cat > .env << 'EOF'67# PostgreSQL68POSTGRES_USER=app69POSTGRES_PASSWORD=secure_postgres_password70POSTGRES_DB=app7172# PgAdmin73PGADMIN_EMAIL=admin@example.com74PGADMIN_PASSWORD=secure_pgadmin_password75EOF7677# 3. Start the services78docker compose up -d7980# 4. View logs81docker compose logs -fOne-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 | bashTroubleshooting
- 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
Components
pgbouncerpostgresqlpgadmin
Tags
#pgbouncer#postgresql#connection-pooling#performance
Category
Database StacksAd Space
Shortcuts: C CopyF FavoriteD Download