Articles

504 vs 503: What Actually Triggers Each in nginx, ALB, and Cloudflare

A deep dive into why nginx, AWS Application Load Balancer, and Cloudflare return 503 or 504 errors, what each code signals, and how to triage them efficiently.

Written by:
APin

Senior Technology Analyst • Verified Expert

More from this author
504 vs 503: What Actually Triggers Each in nginx, ALB, and Cloudflare

A deep dive into why nginx, AWS Application Load Balancer, and Cloudflare return 503 or 504 errors, what each code signals, and how to triage them efficiently.

Understanding 503 vs 504: Core Differences

In HTTP/1.1 the 5xx class signals that the server, acting as a gateway or proxy, cannot fulfill the request. The distinction between 503 Service Unavailable and 504 Gateway Timeout is fundamental: 503 indicates an upstream component is refusing the request outright (an availability problem), whereas 504 means the upstream accepted the connection but failed to produce a response within the configured deadline (a latency problem).

When a client receives 503, the immediate implication is that the downstream service is either down, unhealthy, or deliberately shedding load. The request never reaches the business logic; the gateway aborts early. By contrast, a 504 response tells the client that the request reached a healthy target, but the target’s processing time exceeded the gateway’s timeout window, so the client experiences a timeout after the request was accepted.

  • Availability problem (503): no healthy target, health‑check failure, rate‑limit or WAF block.
  • Latency problem (504): slow query, un‑timed downstream call, large payload upload, or any operation that exceeds the idle timeout.

Practical example in nginx: if the upstream server establishes a TCP connection but then pauses longer than proxy_read_timeout, nginx emits a 504. Nginx never generates a 503 for a slow upstream; a 503 from nginx usually originates from limit_req rate‑limiting or an application‑layer response that explicitly returns 503.

In AWS Application Load Balancer (ALB), a 503 appears when the target group has no healthy instances—e.g., a deployment temporarily removes all targets from rotation. A 504 occurs when a healthy target accepts the request but does not respond before the ALB’s idle timeout (default 60 seconds, configurable up to 4000 seconds).

For Cloudflare, a 503 means Cloudflare itself is refusing the request—often due to a WAF rule or rate limit—so the origin may never be involved. A 504 from Cloudflare usually indicates an intermediate proxy timed out before reaching the origin, while Cloudflare’s proprietary 524 code signals that the TCP handshake succeeded but no HTTP response arrived within Cloudflare’s own timeout window.

Understanding whether the failure is an availability (503) or latency (504) issue directs the first remediation step: verify health‑check status and deployment state for 503s, and profile the slow operation or extend the appropriate timeout for 504s.

nginx: When Does It Emit 503 and 504?

In NGINX the distinction between HTTP 503 and HTTP 504 is rooted in how the proxy module treats upstream communication. The proxy_read_timeout directive does not represent a total request‑deadline; it defines the maximum idle interval between two successive reads from the upstream socket. If the upstream server establishes the TCP connection but then remains silent longer than this interval, NGINX aborts the connection and returns a 504 Gateway Timeout. The timeout is triggered on a “gap‑between‑reads”, not on the overall duration of the response.

Consequently, a backend that streams data slowly but continuously (e.g., a large file download or a long‑running JSON stream) will not cause a 503. Even if the whole transaction exceeds the configured timeout, as long as data keeps arriving before each proxy_read_timeout expires, NGINX will forward the response to the client.

NGINX emits a 503 Service Unavailable only in two situations:

  • When limit_req rate‑limiting is configured to return 503 after the request rate exceeds the defined threshold.
  • When the upstream application itself generates a 503 response (for example, a framework‑level circuit‑breaker or load‑shedding mechanism).

Below is a minimal configuration that illustrates both behaviours:

http {
    # 504 on upstream silence > 30 s
    proxy_read_timeout 30s;

    # 503 when request rate > 10 r/s, burst 5, return 503
    limit_req_zone $binary_remote_addr zone=rl:10m rate=10r/s;
    limit_req zone=rl burst=5 nodelay;
    limit_req_status 503;
}

Practical troubleshooting steps:

  1. Observe the NGINX error log for messages such as upstream timed out (110: Connection timed out) while reading response header from upstream. This indicates a 504 caused by proxy_read_timeout.
  2. Check for limit_req directives or application‑level health‑checks that deliberately return 503. Removing or adjusting the rate‑limit will stop the 503s.
  3. If a slow backend is the root cause, increasing proxy_read_timeout merely postpones the 504; the underlying performance issue (e.g., long database query, exhausted connection pool) must be addressed.

Understanding that NGINX never produces a 503 for a merely slow upstream helps engineers focus on the correct remediation path: tune timeouts for genuine latency problems and adjust rate‑limiting or application logic for availability‑related 503s.

AWS ALB: Health Checks vs Idle Timeout

AWS Application Load Balancer (ALB) distinguishes two fundamentally different failure modes with separate HTTP status codes. When the load balancer cannot find any healthy targets in a target group, it returns 503 Service Unavailable. When a target accepts the TCP connection but does not produce a complete response before the ALB’s idle timeout expires, the ALB returns 504 Gateway Timeout. Understanding the trigger for each code is essential for correct triage.

503 – No Healthy Targets

The ALB performs health checks against each registered target on a configurable path, interval, and success threshold. If every target fails its health check, the target group is marked unhealthy and the ALB has no endpoint to forward traffic to. In this state the ALB immediately generates a 503 without contacting any backend.

  • Typical causes: a recent deployment that removed instances from service, a mis‑configured health‑check path, or a network ACL that blocks health‑check probes.
  • Immediate remediation steps: verify the health‑check configuration, confirm that the target instances are running, and check security‑group rules that might block the probe.

504 – Idle‑Timeout Expiration

When at least one target is healthy, the ALB forwards the request. The idle_timeout (default 60 seconds, configurable up to 4000 seconds) defines the maximum period of inactivity on the established connection. If the target does not send any data before this timer elapses, the ALB aborts the connection and returns a 504.

  • Common scenarios: a long‑running database query, an external API call without a client‑side timeout, or a large file upload that exceeds the timeout.
  • Health checks may still succeed because they hit a lightweight endpoint, so a healthy target can still produce 504s on real traffic.

Practical Example

# ALB idle timeout increase (AWS CLI)
aws elbv2 modify-load-balancer-attributes \
    --load-balancer-arn arn:aws:elasticloadbalancing:region:account-id:loadbalancer/app/my-alb/50dc6c495c0c9188 \
    --attributes Key=idle_timeout.timeout_seconds,Value=300

Increasing the timeout to 300 seconds may prevent a 504 for a known long‑running operation, but it does not address the underlying performance issue. The preferred approach is to profile the backend, add asynchronous processing, or implement client‑side timeouts.

Key Takeaways for Engineers

  • 503 → availability problem: verify target registration and health‑check settings before inspecting application code.
  • 504 → latency problem: measure the actual request duration, optimize the backend, and only then consider extending the idle timeout.
  • Both codes are distinct; treating a 504 as a 503 (or vice‑versa) leads to misdirected incident response.

Cloudflare: 503, 504, and the Unique 524 Code

Cloudflare distinguishes three 5xx responses that often appear together in logs but have fundamentally different origins. Understanding the trigger for each code is essential before deciding whether to adjust time‑outs, modify rate‑limit policies, or investigate upstream performance.

Trigger matrix

  • 503 – Cloudflare block/rate‑limit: The edge network itself refuses the request. Typical causes are a WAF rule, a configured rate‑limit, or an edge‑node outage. The origin server may never see the request.
  • 524 – Origin never answered: The TCP handshake to the origin succeeds and Cloudflare forwards the HTTP request, but no HTTP response is received within Cloudflare’s timeout window (≈100 s on standard plans, longer on Enterprise). This indicates the origin is reachable but not responding.
  • 504 – Intermediate hop timeout: Cloudflare receives a timeout from a proxy, load balancer, or other hop that sits between Cloudflare and the origin. The request never reaches the origin because the upstream hop aborts the connection.

Practical examples

Example 1 – Rate‑limit breach: A public API receives 10 000 requests per minute from a single IP. A Cloudflare rate‑limit rule set to 5 000 requests/minute returns 503 for the excess calls. The origin logs show no traffic for those requests.

Example 2 – Slow backend: An application server processes a complex report that takes 120 seconds. Cloudflare forwards the request, the TCP connection is established, but the server does not emit any HTTP headers within the 100 s window. Cloudflare returns 524, while the server eventually finishes the work.

Example 3 – Misconfigured internal LB: An internal load balancer between Cloudflare and the origin has an idle timeout of 30 seconds. When a client uploads a large file, the LB aborts the connection after 30 seconds, causing Cloudflare to emit a plain 504.

Triaging checklist

  • Identify the code (503, 524, 504) in the edge logs.
  • For 503, review Cloudflare firewall rules, rate‑limit policies, and edge health status.
  • For 524, measure response latency at the origin and verify that the origin emits headers before the Cloudflare timeout.
  • For 504, inspect any intermediate proxies or load balancers for idle‑timeout settings or connectivity issues.
  • Adjust time‑outs only after confirming that the underlying latency or configuration problem is understood; increasing a timeout merely delays the symptom.

Practical Triage and Remediation Steps

Before applying any remediation, understand what each 5xx code represents in the load‑balancing stack. In AWS Application Load Balancer (ALB) a 503 indicates that the target group has no healthy instances – the load balancer cannot route the request at all. A 504 means a target accepted the connection but failed to produce a response before the ALB idle timeout (default 60 s). Cloudflare’s 524 is similar to a 504 but occurs after the TCP handshake succeeds and Cloudflare receives no HTTP response within its own timeout window (≈100 s). Recognizing the difference between an availability failure (503) and a latency failure (504/524) determines the first triage step.

Quick reference checklist

  • 503 – target‑group health
    • Run aws elbv2 describe-target-health --target-group-arn … to verify health‑check status.
    • Inspect recent deployments or scaling events that may have deregistered instances.
    • Confirm that security groups and NACLs allow the health‑check port.
  • 504 – slow operation
    • Instrument the request path (e.g., using curl -w "%{time_total}" or APM tracing) to capture the actual response time.
    • Identify long‑running database queries, external API calls, or large file uploads that exceed the ALB idle timeout.
    • Adjust the idle timeout only as a temporary measure; the root cause is the slow backend.
  • 524 – origin latency
    • From the edge, test the origin directly (e.g., curl -v https://origin.example.com) and measure time_starttransfer.
    • Check for upstream proxies or firewalls that may be delaying the HTTP response.
    • Ensure the origin server can handle the concurrent connection count expected from Cloudflare.

When a timeout increase is proposed, treat it as a stop‑gap. Raising proxy_read_timeout in nginx or the ALB idle timeout merely postpones the failure; it does not resolve the underlying performance bottleneck such as an un‑indexed query or a downstream service without its own timeout.

Example remediation flow for a 504:

  1. Capture the request latency with tracing tools.
  2. Locate the slow component (e.g., a Redis call taking >30 s).
  3. Apply a targeted fix – add caching, optimize the query, or add a circuit‑breaker.
  4. Validate that the end‑to‑end response now completes well under the ALB idle timeout.

Following this disciplined approach keeps the system observable, limits unnecessary configuration changes, and aligns remediation with the actual failure mode indicated by the HTTP status code.

Editorial Policy & Research Methodology

Our findings are based on rigorous internal research, verified industry benchmarks, and direct technical implementation experience from our enterprise client projects. All statistics and technical claims are reviewed by senior engineers before publication to ensure accuracy, transparency, and helpfulness for our readers.

Have an Idea?

Let's Build Something Amazing Together.