Docker: Run PgBouncer using Docker Compose
Connecting to a PostgreSQL directly is the easiest way. But sometimes, you need a Connection Pool. This is how you can use PgBouncer in Docker Compose.
The easiest way to connect an application to a database is a direct connection. But sometimes, you need a connection pool. It reduces
- latencies
- overhead of opening and closing database connections
- the number of concurrent connections
Bur for sure, there are disadvantages:
- additional need of systems and/or hardware
- additional software (which has to be patched and monitored)
- additional configuration
In my case, I run Linkwarden on Docker, and the database is a free PostgreSQL cloud service. This service has
- no fees
- automatic backup
- Automatic patching
But there are also some caveats:
- small amount of connections allowed
- only a few GB of storage
You'll also have to decide
- where to configure connection pooling - database or application side?
- if you need redundancy - maybe 2 or more connection pools and/or a load balancer?
My only problem connecting Linkwarden to this database was the amount of connections. So I decided to run PgBouncer between Linkwarden and the database to reduce the number of connections.
My configuration file looks like this:
[...]
pgbouncer:
image: edoburu/pgbouncer:latest
hostname: pgbouncer-linkwarden
restart: always
environment:
- DB_HOST=<db_host>
- DB_PORT=<db_port>
- DB_USER=<db_user>
- DB_PASSWORD=<db_password>
- DB_NAME=*
- POOL_MODE=transaction
- AUTH_TYPE=trust
- AUTH_USER=linkwarden
- DEFAULT_POOL_SIZE=5
- MIN_POOL_SIZE=0
- MAX_CLIENT_CONN=1000
[...]This configuration is defined within the same docker-compose.yml file.
Parameters:
- DB_HOST: my cloud database service hostname
- DB_PORT: my cloud database service port
- DB_USER: my cloud database service username
- DB_PASSWORD: my cloud database service user password
- DB_NAME:
*allows all databases - POOL_MODE:
transactionmakes a connection valid only for a transaction. Other valid values:session,statement - AUTH_MODE:
trustignores authentication. I used It because my environment is secure enough, and the connection from my application to the connection pool is established only between to docker containers, without open ports - AUTH_USER: as I connect without password, the user is forced to be
linkwarden. - DEFAULT_POOL_SIZE: In this case,
5is set. Only 5 connections are established to the database. - MIN_POOL_SIZE: In this case,
0is set. This means that if no connection is needed, there's also no connection established. - MAX_CLIENT_CONN: is set to
1000. PgBouncer won't provide more than 1000 connections. In my case, this will never be needed
After the PgBouncer container is configured, your application has to be linked to it. Instead of using the cloud service parameters, use these from PgBouncer configured in Docker:
- HOST_NAME from
hostname - PORT is 5432 by default (shouldn't be difficult to change, but doesn't matter)
- credentials like username and password will be the same
Pulling and starting the image is quite easy:
# docker compose pull
# docker compose up -d --remove-orphansThe log files will show something like this:
pgbouncer-1 | 2026-07-24 13:56:21.668 UTC [1] LOG C-0xeefa41f486a8: linkwarden/linkwarden@172.19.0.5:58516 login attempt: db=linkwarden user=linkwarden tls=no replication=no
pgbouncer-1 | 2026-07-24 13:56:21.668 UTC [1] LOG C-0xeefa41f48990: linkwarden/linkwarden@172.19.0.5:58518 login attempt: db=linkwarden user=linkwarden tls=no replication=noThe application - in my case Linkwarden - should work now 😄
And if there's a problem: unless you disabled login using the direct way, you'll always be able to revert your configuration back to the old configuration.