504 Gateway Timeout
Published 17 September 2026
A 504 gateway timeout is the most-blamed-on-the-network error there is, and one of the least deserving. Before anything else: the fact you got a 504 at all proves your connection worked. The waiting happened between two of their servers, long after your request had safely arrived.
What a status code proves
This is the part that settles most arguments. For any HTTP status code to reach you, five things had to succeed in order:
- The hostname resolved to an address.
- A TCP connection opened to it.
- TLS negotiated, if it was https.
- Your request was delivered intact.
- A response travelled back to you.
A 504 is a reply. Something at the other end composed it and sent it to you successfully. If the network between you and that server were broken, you would not have a number at all: you would have a timeout with no response, which is a different thing entirely and looks different.
So what actually timed out?
The clue is in the word gateway. A 504 comes from a machine acting as a middleman: a reverse proxy, a load balancer, an API gateway, a CDN edge. That machine took your request and passed it to a backend server behind it. Then it waited. The backend did not answer in time, so the gateway gave up and told you so.
Both machines belong to them. Your request finished its journey when it reached the gateway; everything after that is an internal conversation you are not part of.
| Stage | Who owns it | Did it work? |
|---|---|---|
| You → their gateway | You and the internet | Yes, or there would be no 504 |
| Their gateway → their backend | Them | No: this is what timed out |
| Their gateway → you | You and the internet | Yes: the 504 arrived |
This is why a 504 can take thirty seconds to appear and still be proof the network is healthy. You were connected, patiently, for the entire duration of somebody else's internal wait.
504 versus 502 versus 503
These three get used interchangeably in tickets and they mean genuinely different things.
| Code | What the gateway experienced |
|---|---|
| 502 Bad Gateway | The backend answered, but with something that was not usable HTTP. It spoke, and what it said was nonsense. |
| 504 Gateway Timeout | The backend did not answer at all within the limit. Silence, not nonsense. |
| 503 Service Unavailable | Usually no backend was involved. The server itself decided it would not serve you: overloaded, or in maintenance. |
A 503 is often deliberate. A 502 and a 504 are not.
If you own the server
The question is never "why is nginx erroring": nginx is reporting faithfully. It is "what is the backend doing for that long?"
- Look at the backend, not the proxy. The access log shows the 504; the reason is in the application log, and often there is no corresponding entry at all because the request is still running.
- Find the slow dependency. Almost every 504 traces to one query, one external API call, or one lock. The gateway timeout is a symptom of something downstream having no timeout of its own.
- Resist raising the timeout first. It is the fastest
fix and it converts a fast failure into a slow one. Raising
proxy_read_timeoutfrom 60 to 300 means users now wait five minutes for the same error. Do it only once you know what the wait is for. - Check the backend is not simply gone. A backend that has crashed and is not accepting connections usually produces a 502 rather than a 504. One that accepts connections and never replies, perhaps because of a full thread pool or a deadlock, produces exactly this.
If you do not own it
There is nothing on your side to fix, and that is worth establishing quickly so the time goes somewhere useful.
- Retry once. Many 504s are transient load.
- Check whether it is only you. If the same URL 504s from a different network and a different machine, it is theirs and it is universal. If it only happens from your office, that is the one scenario worth investigating locally, and it usually turns out to be a proxy of your own adding a timeout.
- Look at the response headers. A
cf-rayheader means Cloudflare produced it, which locates the failure between Cloudflare and the origin rather than at the origin itself. Cloudflare also has its own codes for this: a 524 is the same shape of problem stated more precisely.
Get the verdict in one request. The
HTTP status checker fetches the URL,
follows every redirect, and says plainly whether the fault is yours,
theirs, or genuinely the network: plus the headers that change the
answer, like cf-ray and retry-after.
When the network really is to blame
Not never: just not here. The failures that genuinely implicate the network are the ones with no status code at all, because no round trip ever completed:
- Connection refused. Something replied and said no. The path works; nothing is listening. See no route to host for telling refused, timed out and unreachable apart.
- Connection timed out with no response. Silence is what a firewall looks like.
- DNS failure. Nothing was even attempted.
- TLS handshake failure. The connection succeeded, so the network worked, but the two sides could not agree: which source said it matters.
- A request that hangs only on large payloads. That is usually MTU, and it looks like an application fault: the SSH version of the same problem is the clearest example.
If you have a 504, you have none of those. You have a reply, which means the network delivered your request and delivered their answer. The next conversation belongs to whoever owns the backend.