Prevent Too Many Connections in High-Concurrency n8n Deployments?

Hi guys
I’m running n8n with multiple workers, and as concurrency increases, I’m starting to think about PostgreSQL connection management.
My architecture is roughly:Load Balancer

Multiple n8n Workers

PostgreSQL
My concern is that if every worker opens multiple database connections, the database could eventually hit its connection limit, affecting workflow performance and stability.
I’m considering using a connection pooler like PgBouncer, but I’d like to understand how others manage this in production.
For those running PostgreSQL with high-concurrency n8n deployments:
How do you decide on the right max_connections setting?
Do you use a connection pooler like PgBouncer, or is PostgreSQL’s default behavior enough?
How do you monitor for connection exhaustion before it becomes a problem?
Have you found that increasing worker count or optimizing queries has a bigger impact on overall database performance?

Describe the problem/error/question

What is the error message (if any)?

Please share your workflow

(Select the nodes on your canvas and use the keyboard shortcuts CMD+C/CTRL+C and CMD+V/CTRL+V to copy and paste the workflow.)

Share the output returned by the last node

Information on your n8n setup

  • n8n version:
  • Database (default: SQLite):
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via (Docker, npm, n8n cloud, desktop app):
  • Operating system:

Hey @Keira_Becky, while you wait for a response, here are some things that might help:

Suggested resources

Automatically matched to your question.

Docs:

Forum:

@Wouter_Nigrini, @Yo_its_prakash, @jcuypers - you’ve helped with similar issues before, can you take a look?

Automatically suggested by n8n’s community bot. It’s a pilot - please share feedback here.

Hi @Keira_Becky A good approach is to optimize connection usage before increasing the connection limit.

Recommended approach
Instead of continuously raising max_connections, use a connection pooler like PgBouncer to reuse existing connections efficiently.

n8n Workers

PgBouncer

PostgreSQL

This reduces connection overhead and helps PostgreSQL handle higher concurrency more efficiently.

Best practices
Use connection pooling for multiple workers
Set max_connections based on your server’s CPU and memory
Monitor active, idle, and waiting connections
Optimize slow queries before adding more workers

Keep an eye on: Active connections
Idle connections
Connection wait time
Query latency
CPU and memory usage

In production, connection pooling and query optimization usually provide better scalability than simply increasing PostgreSQL’s connection limit.

In a standard n8n deployment, the formula isn’t just workers * 1. Each worker process can maintain a pool of connections.

The Calculation Logic:

  • Main Instance: Needs a few connections for the UI, API, and scheduler.
  • Workers: Each worker process typically maintains a small pool. If you have 10 workers and each allows a pool of 10, you’re at 100 connections just for workers.
  • Overhead: Postgres allocates memory for each connection (roughly 2-10MB depending on work_mem). Setting max_connections too high (e.g., 5000) without sufficient RAM will cause the OS to kill Postgres via the OOM killer.

Recommendation: Start with max_connections = 200-500 for mid-sized deployments. If you exceed this, do not simply keep increasing the number; move to a pooler.

PgBouncer is for high-concurrency production environments.

PostgreSQL’s default behavior is “one process per connection,” which is expensive. PgBouncer acts as a lightweight proxy that manages a pool of “real” connections to the DB while allowing thousands of “virtual” connections from n8n workers.

Does that help?

Hi @Keira_Becky
The per-process lever is DB_POSTGRESDB_POOL_SIZE, which defaults to 2, so the footprint is roughly (main processes + workers + webhook processors) times that value, and you size the database around that figure instead of estimating from worker count. Raise it per process only when workers are actually waiting on the pool.
Scale by running fewer workers at higher concurrency rather than many workers at low concurrency, n8n recommends 5 or higher per worker because a large number of low-concurrency workers exhausts the connection pool and causes delays and failures:

n8n worker --concurrency=10

@Niffzy

Do you use PgBouncer in transaction mode or session mode with n8n? If you’ve tried both, what differences did you notice in production?

It depends on your workload, but for most high-concurrency applications, transaction pooling is often preferred because it allows connections to be reused more efficiently and supports a larger number of concurrent clients.

Session pooling can be a better choice if your application relies on session-specific features, such as temporary tables or session variables, since each client keeps the same database connection for the entire session.

Before choosing a mode, I’d test it in a staging environment and verify that your n8n workflows don’t depend on session-specific behavior. Then monitor connection usage, query latency, and overall throughput to confirm it’s performing as expected.

In general, the best choice depends on how your application uses database connections, so it’s worth validating with production-like workloads before deploying.