504 Gateway Timeout means a proxy or gateway (nginx, Cloudflare, a load balancer, an API gateway) forwarded the request to the server behind it and gave up waiting for a response. The connection worked, but the upstream was too slow. It may even finish the work after the client has already seen the error.
HTTP/1.1 504 Gateway Time-out
Server: nginx
Content-Type: text/html
<html><head><title>504 Gateway Time-out</title></head>
<body><center><h1>504 Gateway Time-out</h1></center><hr><center>nginx</center></body></html>
Common causes
- A slow request. A heavy database query, a report, an export, or a call to a slow third-party API, all inside the request.
- An overloaded upstream. Requests queue behind busy workers until they time out.
- A stuck dependency. The app waits on a database lock, a hung connection or a downstream service with no timeout of its own.
- Network problems between the proxy and the upstream: a firewall silently dropping packets, or a wrong IP that never answers.
- Mismatched timeouts. A proxy with a 30-second timeout in front of a job that routinely takes 45.
How to fix it as a visitor
Wait and try again. If you were submitting something like a payment or a form, check whether it went through before resubmitting, because the server may have finished the work after the timeout.
How to fix it as a developer or ops
| Where | What you see | Default timeout | Setting |
|---|---|---|---|
| nginx | upstream timed out (110: Connection timed out) while reading response header from upstream | 60s | proxy_read_timeout, fastcgi_read_timeout for PHP-FPM |
| Cloudflare | Error 524: A timeout occurred | 100s | Raised only on Enterprise; otherwise make the origin respond faster |
| AWS ALB | 504 in access logs | 60s idle timeout | Load balancer attribute idle_timeout.timeout_seconds |
| AWS API Gateway | 504 / Endpoint request timed out | 29s for REST integrations | Integration timeout |
Raising a timeout is fine when a request is legitimately long. More often, the real fix is in the app:
- Find the slow part. APM traces, slow query logs or timing logs around external calls.
- Move long work out of the request. Accept the job, return
202 Acceptedwith a job ID, and let the client poll or receive a webhook when it's done. - Put timeouts on outbound calls, shorter than the proxy's, so the app can return a clean error instead of hanging.
- Add capacity if requests are timing out in a queue rather than in your code.
504s and timeouts on a webhook endpoint
Webhook senders wait only a short time for your response, usually a few seconds to a few tens of seconds. If your handler does the work inline (calls an API, writes several rows, sends an email), a slow moment turns into a timeout, the provider records a failure and retries. Your handler may have actually finished, so the retry becomes a duplicate.
The pattern that avoids it: verify the signature, store the raw event, return 200, process asynchronously. Then make processing idempotent so a retried delivery doesn't run twice.
If timeouts come from bursts, Webhook Relay throttling limits the rate or number of concurrent deliveries to your endpoint so it isn't flooded. And durable retries keep each event and retry with exponential backoff for up to 30 days, so a slow afternoon never loses data. For webhooks forwarded to localhost through relay forward, a provider reporting a timeout can also mean the agent couldn't reach your local server. See 502 Bad Gateway for that case.
When to return 504 from your own service
Return 504 only when your service is a gateway or proxy and the upstream it called didn't answer in time. If your own handler is slow, fix the handler or return 202 Accepted and finish the work in the background. For a timeout that happens because the client was too slow to send the request, the code is 408 Request Timeout.
