DEVESSENTIALS

HTTP 504 Gateway Timeout

A 504 comes from a proxy, load balancer or CDN that forwarded the request and stopped waiting before an answer came back. The upstream may still be working on the request, and may even finish it, but the client already has an error.

5xx · Server errorRFC 9110 §15.6.5

504 Gateway Timeout

A gateway or proxy didn't receive a timely response from the upstream server.

Who fixes it: Server. The upstream is too slow for the proxy's timeout. Fix the slowness, or raise the timeouts at every layer.

What 504 means

That matters for non-idempotent requests: a POST /payments that got a 504 may have succeeded. Clients should check before retrying, or use idempotency keys.

The fix is either to make the upstream faster or to raise the timeout at every layer between client and app. Raising timeouts alone usually just moves the problem.

Source: RFC 9110 §15.6.5.

Common causes

  • nginx proxy_read_timeout (default 60s) expired. The error log shows upstream timed out (110: Connection timed out) while reading response header from upstream.
  • A slow database query (missing index, lock wait) or an external API call with no timeout of its own.
  • A load balancer's idle timeout is shorter than the request. AWS ALB defaults to 60 seconds. Cloudflare waits 100 seconds for the origin by default and reports a timeout with its own 524 code, not 504.
  • Vercel: the function exceeded its maximum duration, reported as 504: FUNCTION_INVOCATION_TIMEOUT.
  • PHP-FPM behind nginx: fastcgi_read_timeout (60s by default) or PHP's max_execution_time.
  • The upstream is unreachable at the network level (a firewall silently dropping packets, a wrong security group), so the connection attempt times out after proxy_connect_timeout.
  • Worker starvation: all workers are busy, so new requests queue until the proxy gives up.

How to debug and fix a 504

Measure where the time goes

Time to first byte through the proxy vs directly from the app tells you whether the app is slow or the path to it is.

curl -s -o /dev/null \
  -w 'connect: %{time_connect}s  ttfb: %{time_starttransfer}s  total: %{time_total}s\n' \
  https://example.com/api/report

# Bypass the proxy
curl -s -o /dev/null -w '%{time_total}s\n' http://127.0.0.1:3000/api/report

nginx: raise timeouts only where needed

Keep the connect timeout short so an unreachable app fails fast, and raise the read timeout only for the slow endpoints.

location /api/reports/ {
    proxy_pass http://127.0.0.1:3000;
    proxy_connect_timeout 5s;     # fail fast if the app is unreachable
    proxy_send_timeout    120s;
    proxy_read_timeout    120s;   # default 60s
}

# PHP-FPM equivalent
location ~ \.php$ {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_read_timeout 120s;
}

Next.js on Vercel: maxDuration

Set the route segment config in the route or page. The maximum allowed value depends on your plan.

// app/api/report/route.ts
export const maxDuration = 60; // seconds

Move long work out of the request

If a job takes minutes, no timeout setting is the right fix. Accept it with 202, process it in a queue, and let the client poll.

POST /api/reports          -> 202 Accepted
                              Location: /api/reports/jobs/91
GET  /api/reports/jobs/91  -> 200 {"status": "running"}
GET  /api/reports/jobs/91  -> 200 {"status": "done", "url": "/files/report-91.csv"}

Headers that matter with 504

Server-Timing
Have the app report where time goes (Server-Timing: db;dur=850, render;dur=120). Browsers show it in DevTools' Timing tab.
Retry-After
Optional. Clients should retry idempotent requests with backoff.

504 vs similar status codes

  • 502 Bad Gateway: The upstream responded badly or not at all (refused, reset). 504 means it was simply too slow.
  • 503 Service Unavailable: The service declined the request up front, e.g. maintenance or overload.
  • 408 Request Timeout: The reverse case: the server timed out waiting for the client to send its request.

SEO impact of 504

Timeouts count as server errors for Googlebot: it slows crawling, and pages that time out repeatedly can drop out of the index. Slow responses also reduce how much of a large site gets crawled, so fixing the slow query does more than raising the timeout.

Related status codes

Looking for another code? Search the full HTTP status codes list, or read which code your API should return in the REST API status codes guide.

Learn more

Browse all developer guides →

Frequently Asked Questions

What causes a 504 Gateway Timeout?▾

A proxy, load balancer or CDN waited longer than its timeout for the backend. The usual root causes are slow database queries, slow third-party API calls, overloaded workers, or a network path to the backend that silently drops packets.

How do I increase the timeout in nginx?▾

Set proxy_read_timeout (and proxy_send_timeout) in the location that proxies to your app, for example proxy_read_timeout 120s;, then reload nginx. For PHP-FPM use fastcgi_read_timeout. Raise the load balancer and CDN timeouts too, since the shortest one wins.

Is it safe to retry a request that got a 504?▾

For GET and other idempotent requests, yes, with backoff. For POST requests the server may have finished the work after the proxy gave up, so a retry can duplicate it. Use idempotency keys or check the resource's state first.