Nginx

Nginx 503 Service Temporarily Unavailable Under High Traffic Load

A 503 specifically appearing under high traffic load, rather than consistently, means Nginx (or the application behind it) is running out of capacity to handle the current volume of requests — the fix depends on identifying exactly which layer is actually exhausted, since Nginx itself, its upstream connections, and the backend application can each independently become the bottleneck.

The Problem

Under normal traffic, everything works fine. During a spike — a marketing campaign, a viral moment, a load test — requests start failing:

503 Service Temporarily Unavailable
nginx

The failures might be intermittent (some requests succeed, others fail) or become the dominant response once traffic crosses a certain threshold.

Why It Happens

A 503 from Nginx under load typically means Nginx itself has decided it cannot currently service the request, distinct from a 502 (bad response from upstream) or 504 (upstream too slow) — common specific causes:

  • Nginx's own worker_connections limit is being reached, meaning Nginx itself can't accept more connections until existing ones free up
  • An upstream backend pool is exhausted — all backend servers/workers are busy handling existing requests, and Nginx has no available upstream to forward new requests to
  • A rate limiting or connection limiting configuration (limit_req or limit_conn) is intentionally rejecting excess requests once a configured threshold is crossed, which is often working exactly as configured but simply configured too conservatively for genuine traffic spikes
  • The backend application itself is returning 503 responses under load (many application frameworks do this deliberately when their own internal capacity, like a database connection pool, is exhausted), and Nginx is simply passing that response through unchanged

The Fix

First, identify which layer is actually the source by checking Nginx's error log during the traffic spike, which typically distinguishes between these different causes with specific log message patterns:

tail -f /var/log/nginx/error.log

Look for messages mentioning "limiting requests," "no live upstreams," or worker connection limits specifically, each pointing toward a different fix.

If Nginx's own worker_connections is the limit being hit, raise it, along with confirming the underlying system file descriptor limit supports the higher value:

events {
    worker_connections 4096;
}

If rate limiting (limit_req) is intentionally rejecting legitimate traffic during genuine spikes, review whether the configured rate is actually appropriate for real traffic patterns, versus being tuned only for the (much lower) traffic you tested against during initial setup:

limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

location /api/ {
    limit_req zone=api burst=20 nodelay;
}

Increasing both the base rate and the burst value allows Nginx to accommodate a higher, more realistic legitimate traffic ceiling, while still providing meaningful protection against genuine abuse at a level beyond that.

If the upstream backend pool itself is exhausted (all backend workers/processes busy), the actual fix is scaling the backend — adding more application server instances or workers — rather than anything configurable purely within Nginx, since Nginx is correctly reporting that it has no available upstream capacity to forward requests to:

upstream backend {
    server backend1:3000;
    server backend2:3000;  # add more backend instances to handle increased load
    server backend3:3000;
}

If the backend application itself is the one returning 503 under load (check by testing the backend directly, bypassing Nginx, under similar load conditions), the fix is addressing the backend's own capacity limits — its own connection pool size, worker process count, or database connection limits — rather than anything in Nginx's configuration at all.

Still Not Working?

If you've ruled out configuration limits and confirmed the backend has adequate capacity, but 503s still appear under genuinely high load, consider whether the traffic spike exceeds what your current infrastructure can reasonably handle at all, regardless of configuration tuning — in that case, the appropriate response is horizontal scaling (adding more server capacity, potentially behind a load balancer distributing across multiple Nginx/backend instances) rather than continuing to search for a configuration-only fix to what's fundamentally a capacity problem beyond what a single server, however well-tuned, can absorb.