Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for NGINX By James Joyner IV · · 9 min read

NGINX Error Guide: 'worker_connections are not enough' Connection Pool Exhaustion

Fix NGINX 'worker_connections are not enough' by raising worker_connections in the events block and aligning the file descriptor limit on each worker.

  • #nginx
  • #troubleshooting
  • #errors
  • #limits

Exact Error Message

When NGINX runs out of connection slots inside a worker process, it logs an [alert] to the error log. As a reverse proxy, the message usually mentions the upstream:

2026/06/27 18:05:51 [alert] 2841#2841: *204815 worker_connections are not enough while connecting to upstream, client: 203.0.113.7, server: app.example.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:9000/", host: "app.example.com"

You may also see the shorter, non-proxy variant when NGINX serves files or terminates connections directly:

2026/06/27 18:05:52 [alert] 2841#2841: 1024 worker_connections are not enough

Both come from the same root cause: a single worker process has reached its worker_connections ceiling and cannot accept or open another socket.

What the Error Means

NGINX is event-driven. Each worker process maintains a fixed-size pool of connection slots, sized by the worker_connections directive (default 512, often 1024). A connection slot is consumed by any open socket the worker is managing: an inbound client connection, an outbound upstream connection, a connection to a memcached or FastCGI backend, or a DNS resolver socket.

The critical detail for a reverse proxy is that every proxied request consumes two slots, not one:

  1. One slot for the client connection (browser to NGINX).
  2. One slot for the upstream connection (NGINX to your app server).

So a worker configured with worker_connections 1024 can proxy at most 512 simultaneous requests, not 1024. The while connecting to upstream wording tells you NGINX had a client connection in hand, tried to open the second slot for the backend, and found the pool already full.

This is a per-worker limit. The theoretical ceiling for the whole server is:

max_clients = worker_processes * worker_connections

and for a reverse proxy the useful ceiling is roughly half that:

max_proxied_requests ≈ (worker_processes * worker_connections) / 2

Common Causes

  • worker_connections left at the default. The stock 512 or 1024 is fine for a static file server but quickly exhausted behind a busy reverse proxy where each request is doubled.
  • Traffic spike or slow upstream. If the backend slows down, connections pile up because each one stays open longer, multiplying concurrent slot usage.
  • Keepalive connections. Browser keepalive (and upstream keepalive pools) hold slots open between requests, so idle connections still count against the limit.
  • The file descriptor limit is lower than worker_connections. Each connection needs a file descriptor. If the worker’s RLIMIT_NOFILE is below worker_connections, you hit the fd wall first (a different error) and effectively cap connections early.
  • Too few worker processes. With worker_processes 1, all traffic funnels through a single pool. The total capacity is just one worker’s worth of slots.

How to Reproduce the Error

Set an artificially tiny limit and drive concurrent proxied requests through it. In a test config:

events {
    worker_connections 4;
}

Reload, then fire more concurrent connections than the pool allows. A quick load generator works:

# 100 concurrent connections, 1000 total, against the proxy
ab -n 1000 -c 100 http://app.example.com/

With only 4 slots per worker (2 usable proxied requests), NGINX will log worker_connections are not enough while connecting to upstream almost immediately. Reset the directive afterward.

Diagnostic Commands

All read-only. Start by confirming what NGINX is actually using, since the effective value can come from an included file:

# Validate config and show where the binary thinks the config lives
sudo nginx -t

# Dump the full, resolved config and grep the relevant directives
sudo nginx -T 2>/dev/null | grep -E 'worker_connections|worker_processes|worker_rlimit_nofile'

Check how many connections the box is currently handling so you can size the new limit against reality:

# Socket summary: total, established, etc.
ss -s

# Count established TCP connections
ss -tan state established | wc -l

Confirm the alerts in the journal and check timing against traffic spikes:

journalctl -u nginx --since "1 hour ago" | grep -i "worker_connections"

Inspect the per-worker file descriptor limit. This is the ceiling that worker_connections must respect:

# Soft/hard NOFILE limit for a running worker process
cat /proc/$(pgrep -o nginx)/limits | grep -i "open files"

And confirm your CPU count, since worker_processes auto maps to it:

nproc

If cat /proc/.../limits shows Max open files of, say, 1024 while you want worker_connections 8192, the fd limit is your real bottleneck and must be raised first.

Step-by-Step Resolution

1. Find the current values. Use nginx -T | grep (above) to read the live worker_connections, worker_processes, and any worker_rlimit_nofile.

2. Raise worker_connections in the events block. This directive lives in events {}, not http {}:

events {
    worker_connections 4096;
}

Pick a value based on expected concurrency. For a reverse proxy serving N simultaneous requests per worker, you need at least 2 * N slots, plus headroom.

3. Make sure you have enough workers. Let NGINX match cores:

worker_processes auto;

With auto and an 8-core box, worker_connections 4096 gives a theoretical ceiling of 8 * 4096 = 32768 connections, or ~16k concurrent proxied requests.

4. Align the file descriptor limit. worker_connections must be less than or equal to the per-worker file descriptor limit, since every connection consumes one fd. Set it explicitly in the main context so NGINX raises RLIMIT_NOFILE for its workers:

worker_rlimit_nofile 16384;

A good rule of thumb is worker_rlimit_nofile >= 2 * worker_connections to leave room for log files, upstream sockets, and resolver descriptors. If the OS hard limit is lower, also raise it via systemd (LimitNOFILE= in a drop-in for the nginx unit) or /etc/security/limits.conf, otherwise NGINX cannot exceed the system ceiling.

5. Test and reload. worker_connections takes effect on a reload, not a config re-read, so apply it with:

sudo nginx -t && sudo systemctl reload nginx

6. Verify. Re-run cat /proc/$(pgrep -o nginx)/limits to confirm the new fd limit landed on the workers, and watch the error log to confirm the alerts stop under load.

Prevention and Best Practices

  • Size for the proxy double-count. Always plan around 2 * concurrent_requests per worker when NGINX proxies upstreams.
  • Keep worker_rlimit_nofile ahead of worker_connections. Treat the fd limit as the hard floor; never set worker_connections higher than the worker’s available descriptors.
  • Use upstream keepalive deliberately. A keepalive connection pool to backends reduces connection churn but holds slots open; account for it in your math.
  • Monitor established connections over time. Alert when ss -tan state established | wc -l trends toward your computed ceiling so you raise limits before the alert fires. Connection-pool exhaustion is a great candidate for an automated alert rule, see the monitoring alerts dashboard.
  • Fix slow upstreams. Often the real cause is a backend that got slow, multiplying open connections. Address latency, not just the limit.
  • Too many open files / accept4() failed (24: Too many open files) — this is the file descriptor limit (RLIMIT_NOFILE), a kernel/OS limit, not the NGINX connection-pool limit. They look similar and often co-occur: raising worker_connections without raising worker_rlimit_nofile simply trades one error for the other. Fix the fd limit with worker_rlimit_nofile and the system LimitNOFILE.
  • upstream timed out (110: Connection timed out) while connecting to upstream — backend is slow or unreachable; slow upstreams are a frequent cause of connection pileups that lead to the worker_connections alert.
  • no live upstreams while connecting to upstream — all backends marked down by health checks; unrelated to the pool size but appears in the same proxy log lines.

For more NGINX troubleshooting guides, see the NGINX category.

Frequently Asked Questions

Does worker_connections count both the client and the upstream connection?

Yes. When NGINX acts as a reverse proxy, each request uses two slots from the worker’s pool: one for the inbound client socket and one for the outbound upstream socket. That halves your effective request capacity, so a worker with worker_connections 1024 can handle roughly 512 concurrent proxied requests.

What is the difference between worker_connections are not enough and Too many open files?

worker_connections are not enough means you hit NGINX’s own per-worker connection-pool limit set in the events block. Too many open files means you hit the operating system’s file descriptor limit (RLIMIT_NOFILE). You must keep worker_rlimit_nofile at or above worker_connections, otherwise raising one just exposes the other.

Do I need to restart NGINX after changing worker_connections?

No restart is required; a reload is enough. Run sudo nginx -t && sudo systemctl reload nginx. NGINX spins up new worker processes with the updated pool size and gracefully retires the old ones. A full restart is only needed for some low-level changes like binding new listen sockets.

How high can I set worker_connections?

The practical ceiling is the per-worker file descriptor limit, since every connection needs a descriptor. Set worker_rlimit_nofile first (commonly 2 * worker_connections), make sure the OS hard limit allows it, then raise worker_connections. Values of 409616384 per worker are common on busy proxies with adequate fd limits.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.