Guide
HTTP Status Codes in Nginx Logs (Complete Reference)
The status field is the fastest health check you have. A sudden wall of 5xx means something broke. A spike in 404s means someone is scanning. Here is what each code is telling you.
Status codes live in the $status field of each log line. If you are not sure where that sits, the nginx log format guide walks through the whole line. The first digit tells you the category, and that alone answers most questions.
- 2xx success. The request worked.
- 3xx redirection. The client was sent somewhere else.
- 4xx client error. The request was wrong, blocked, or asking for something that is not there.
- 5xx server error. Nginx or the backend behind it failed.
2xx success
| 200 | OK. The normal response. Most of your log should be this. |
| 204 | No Content. Success, but there is nothing in the body. Common for tracking pixels and API calls that just acknowledge. |
| 206 | Partial Content. A range request, usually video scrubbing or a resumed download. |
3xx redirection
| 301 | Moved Permanently. The canonical redirect. Search engines update their index to the new URL. |
| 302 | Found, a temporary redirect. The original URL stays the one that counts. |
| 304 | Not Modified. The client already has a fresh copy in cache, so nginx sends nothing. Good for bandwidth, and normal for repeat visitors. |
| 308 | Permanent Redirect. Like 301 but the HTTP method is guaranteed to stay the same. |
4xx client errors
This range is where bot and attack traffic shows up. A normal site has some background 404s. A flood of them, especially against paths like /wp-login.php or /.env, is a scanner looking for a way in.
| 400 | Bad Request. Malformed syntax. Often raw bytes or a protocol mismatch, like TLS sent to a plain HTTP port. |
| 401 | Unauthorized. Authentication is required and was missing or wrong. |
| 403 | Forbidden. The server understood the request and is refusing it. Directory denies, IP blocks, and WAF rules land here. |
| 404 | Not Found. The path does not exist. Watch the paths, not just the count. |
| 405 | Method Not Allowed. A POST to something that only accepts GET, for example. |
| 408 | Request Timeout. The client was too slow sending the request. Also seen from idle keep-alive probes. |
| 413 | Payload Too Large. The upload was bigger than client_max_body_size allows. |
| 429 | Too Many Requests. Your rate limiting kicked in. If you see a lot, something is hammering you, or your limit is too tight. |
The nginx-specific codes
Two codes in the 4xx range are not standard HTTP. Nginx invented them for situations real HTTP does not cover, and they confuse people who look them up and find nothing.
| 499 | Client Closed Request. The visitor gave up and closed the connection before nginx could answer. This is not a server fault. A burst of 499s usually means your backend is slow enough that people are leaving, or a bot is firing requests and cancelling them. Check $request_timeagainst these lines to confirm. |
| 444 | No Response. Nginx closes the connection and sends nothing at all. You only see this when you set return 444; yourself, usually to drop obvious junk traffic without wasting a response on it. |
5xx server errors
When nginx acts as a reverse proxy, the 5xx codes split into two stories: nginx itself failing, and the backend behind it failing. Telling them apart saves you from restarting the wrong thing.
| 500 | Internal Server Error. A catch-all. Usually the application threw an unhandled error. Check the app log, not nginx. |
| 502 | Bad Gateway. Nginx reached the backend but got garbage or a dropped connection back. The classic sign your app server crashed or is not listening on the expected port. |
| 503 | Service Unavailable. The backend is up but refusing work, often overloaded or in maintenance mode. Sometimes nginx returns this when all upstreams are marked down. |
| 504 | Gateway Timeout. Nginx reached the backend, waited, and the backend never answered in time. A slow query or a stuck worker. Different from 502: the connection worked, the response just never came. |
The short version for proxy setups: 502 means the backend gave a bad answer or none, 503 means it said it cannot serve right now, and 504 means it went quiet. If 502s and 504s climb together, look at the upstream. If only 500s climb, look at your application code.
Reading the distribution
One status code in isolation rarely tells you much. The shape of the distribution does. A healthy site is mostly 200 and 304, with a thin tail of 404s and redirects. When that shape changes, you have your lead:
- 404s climbing against weird paths means scanning. Pair it with bot detection.
- A jump in 499s points at backend latency driving visitors away.
- Any sustained 5xx is an outage in progress. This is the first thing to alert on.
- A rise in 403 or 429 usually means your own rules are firing, sometimes on real users.
Try the free nginx log analyzer
Drop your access log in and see the full status code breakdown, top error paths, and the IPs behind them. It all runs client-side, so your log stays on your machine.
Open the analyzer