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.

Docker: Run PgBouncer using 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: transaction makes a connection valid only for a transaction. Other valid values: session, statement
  • AUTH_MODE: trust ignores 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, 5 is set. Only 5 connections are established to the database.
  • MIN_POOL_SIZE: In this case, 0 is 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-orphans

The 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=no

The 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.