n8n PostgreSQL high concurrency – connection pool and query optimisation

Optimize n8n with PostgreSQL for high-concurrency workflows, faster execution, and reliable automation performance.


Quick Diagnosis

ProblemQuick Fix
n8n slows with many parallel workflowsLimit DB connections, use pgBouncer, tune PostgreSQL, add indexes
Connection errors under loadReduce N8N_DB_MAX_CONNECTIONS, enable pooler
Long queries or UI lagAdd indexes on execution_entity and monitor locks

 

Following this setup reduces latency from seconds to < 500 ms even with 100+ workflows running concurrently. If you’re still facing basic connection issues before tuning performance, start with our complete guide: n8n PostgreSQL connection not working: SSL, credentials, and network fixes.


1. Why n8n Slows Down?

  • Connection exhaustion: too many workflow DB clients
  • Lock contention: multiple inserts/updates on execution_entity
  • Inefficient queries: default schema lacks covering indexes

Tip: Always monitor pg_stat_activity under load.


2. Limit n8n DB Connections

Set in your Docker environment:

 

- N8N_DB_MAX_CONNECTIONS=20  # ≈ half of PostgreSQL max_connections
Verify pool size:

 

docker exec -it n8n node -e 
    "console.log(require('pg').defaults.poolSize)"

3. Deploy pgBouncer

pgBouncer pools connections, reducing churn.

Minimal Docker setup:

 

pgbouncer:
  image: edoburu/pgbouncer
  environment:
    DB_HOST: postgres
    DB_USER: n8n
    DB_PASSWORD: secret
    POOL_MODE: transaction
    MAX_CLIENT_CONN: 500
    DEFAULT_POOL_SIZE: 30
  ports:
    - "6432:6432"
Quick tuning table:

 

SettingRecommended
pool_modetransaction
max_client_conn500
default_pool_size30 – 50
idle_timeout300s

 

Avoid session mode; it holds a connection for the entire workflow.


 

4. PostgreSQL Tuning:

 

A high-level roadmap for running n8n at scale with PostgreSQL: covering pooling, tuning, monitoring, and high-concurrency workloads.

 

Typical for 8 vCPU / 16 GB RAM:

 

max_connections = 200
shared_buffers = 4GBwork_mem = 64MB
effective_cache_size = 12GB
max_worker_processes = 8
Check Live:

 

SHOW max_connections;
SHOW shared_buffers;
Safety checks:

 

CheckCommand
RAM usageps -o %mem,rss -p $(pidof postgres)
Connection countSELECT count(*) FROM pg_stat_activity;
Lock timeoutSET lock_timeout = ‘5s’;

 


5. Indexes to Reduce Contention

Execution table:

 

CREATE INDEX IF NOT EXISTS idx_execution_workflow_status
ON execution_entity (workflowId, status);

CREATE INDEX IF NOT EXISTS idx_execution_finished_at
ON execution_entity (finishedAt DESC);
Other tables:

 

CREATE INDEX IF NOT EXISTS idx_credential_name
ON credential_entity (name);
CREATE INDEX IF NOT EXISTS idx_workflow_name
ON workflow_entity (name);

Tip: Run ANALYZE; after creating indexes.


6. Query Analysis

Use EXPLAIN ANALYZE to spot slow queries:

 

If your queries run without errors but existing rows still don’t update, this may be an UPSERT logic issue rather than performance. See: n8n PostgreSQL UPSERT not updating existing records

 

EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM execution_entity
WHERE workflowId = $1 AND status = 'running';

Look for Seq Scan → Index Scan improvement.


7. Monitoring

Active queries:

 

SELECT pid, usename, state, now() - query_start AS duration, query
FROM pg_stat_activity
WHERE state <> 'idle'
ORDER BY duration DESC
LIMIT 10;

Top slow queries:

 

SELECT query, calls, total_time, mean_time
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 5;

Add Grafana dashboards for real-time monitoring.


8. Common Errors & Fixes

In some cases, the PostgreSQL node shows success but no data changes. This is usually caused by transaction scope, pooling, or commit behavior. See: n8n PostgreSQL node runs successfully but nothing updates.

SymptomFix
“remaining connection slots”Increase max_connections or reduce N8N_DB_MAX_CONNECTIONS
DeadlocksReorder updates, use FOR UPDATE SKIP LOCKED
Lock timeoutReduce statement_timeout, split batches
pgBouncer refusedVerify host/port point to pgBouncer (6432)

9. Checklist for High-Concurrency Readiness

  • pgBouncer deployed, pool_mode=transaction
  • N8N_DB_MAX_CONNECTIONS ≤ half of max_connections
  • PostgreSQL tuned (shared_buffers, work_mem)
  • Indexes added on execution_entity
  • Monitoring via pg_stat_activity & pg_stat_statements
  • Load-tested for ≥100 concurrent workflows

Related Guides:

 


Conclusion

Optimizing n8n for high-concurrency workloads is all about managing database connections, using connection pooling, tuning PostgreSQL, and indexing key tables. By limiting direct connections, deploying pgBouncer, and monitoring query performance, you can keep workflows running smoothly even under heavy load. Regularly reviewing metrics, analyzing slow queries, and applying indexes ensures your n8n instance remains responsive, reliable, and ready to handle hundreds of simultaneous executions.

Leave a Comment

Your email address will not be published. Required fields are marked *