---
title: PostgreSQL Connection Pooling
description: Add PgBouncer as a connection pooler in front of your Railway PostgreSQL database or HA cluster.
---
Railway can add [PgBouncer](https://www.pgbouncer.org/) as a connection pooler in front of your PostgreSQL service. PgBouncer multiplexes many application connections into a smaller pool of server connections, reducing overhead and allowing your database to serve far more concurrent clients than `max_connections` alone would permit.

PgBouncer works with both standalone Postgres and [Postgres HA](/databases/postgresql-ha) clusters. When added to an HA cluster, it sits in front of HAProxy.

## Adding PgBouncer

Open your Postgres service and navigate to **Database → Config → Connection Pooling**. Click **Add PgBouncer**.

Before confirming, select a pool mode:

| Pool Mode | Behavior |
|---|---|
| **Transaction** _(default)_ | Server connections are reused per transaction — best multiplexing. Session-level features (LISTEN/NOTIFY, advisory locks, `SET` held across statements) are not supported. |
| **Session** | Each client holds a server connection for its entire session. Every Postgres feature works, but pooling only helps when clients disconnect. |
| **Statement** | Server connections are reused per statement. Multi-statement transactions are not allowed. |

Transaction mode is the right choice for most applications. Use session mode if your application relies on session-scoped features that are incompatible with transaction pooling.

After confirming, Railway stages the changes. Deploy to complete the setup.

## Connection strings

Once PgBouncer is deployed, these connection variables are available:

| Variable | Points to | Use for |
|---|---|---|
| `DATABASE_URL` | PgBouncer — private network | Normal application queries from inside Railway |
| `DATABASE_PUBLIC_URL` | PgBouncer — TCP proxy | Connecting from outside Railway |
| `DATABASE_UNPOOLED_URL` | Postgres or HAProxy — private network | Operations that require a dedicated session |
| `DATABASE_PUBLIC_UNPOOLED_URL` | Postgres or HAProxy — TCP proxy | Unpooled connections from outside Railway |

The two public variables exist only while public access is enabled — if your Postgres was publicly exposed before adding PgBouncer, the public endpoint carries over to the pooler automatically; otherwise click **Connect** on the cluster view and add **Public Access**. `DATABASE_PUBLIC_UNPOOLED_URL` bypasses the pooler, so it additionally requires the database behind PgBouncer to be publicly exposed itself.

Railway automatically migrates any service within your project that references your Postgres variables to point to PgBouncer. Hardcoded connection strings outside of Railway must be updated manually.

### When to use `DATABASE_UNPOOLED_URL`

Use `DATABASE_UNPOOLED_URL` for operations that require a dedicated server connection:

- **Schema migrations** — most migration tools open a transaction that spans the entire migration run
- `CREATE INDEX CONCURRENTLY` / `DROP INDEX CONCURRENTLY`
- `LISTEN` / `NOTIFY`
- Advisory locks (`pg_advisory_lock`)
- `SET` configuration values that must persist across statements

For everything else, use `DATABASE_URL`.

## Scaling PgBouncer

The **PgBouncer Overview** panel (available from the cluster view once PgBouncer is deployed) lets you scale the number of PgBouncer replicas from 1 to 6. Each replica multiplies both client capacity and the number of server connections open to Postgres:

| Setting | Default | Description |
|---|---|---|
| `DEFAULT_POOL_SIZE` | 20 | Server connections per replica |
| `MAX_CLIENT_CONN` | 1000 | Max client connections per replica |

With 1 replica: up to 1,000 clients share 20 server connections.
With 3 replicas: up to 3,000 clients share 60 server connections.

Make sure the total server connections across all replicas (`DEFAULT_POOL_SIZE × replicas`) stays within your Postgres `max_connections` limit. The PgBouncer Overview will warn you when server connections approach that limit.

## Changing the pool mode

You can change the pool mode at any time from the **PgBouncer Overview** panel. The change is staged and takes effect on the next PgBouncer deployment — it does not restart your database.

## Removing PgBouncer

To remove PgBouncer, click **Remove** in the PgBouncer Overview, or navigate to **Database → Config → Connection Pooling → Remove PgBouncer**.

Removing PgBouncer will:

- Drop all active PgBouncer connections
- Restore `DATABASE_URL` to point directly at your Postgres service (or HAProxy for HA clusters)
- Remove the `DATABASE_UNPOOLED_URL` variable

Railway automatically migrates variable references within your project back to the original endpoint. Hardcoded connection strings outside of Railway must be updated manually.