HTTP Status Codes Cheatsheet - HTTP Response Status Code Reference
The value of a status code is not memorising the table but collapsing a whole-system guess into one layer. The source of the code decides whom it accuses. 3xx and 4xx mostly point at the client: 3xx means a redirect was not followed, 4xx means the request itself, the identity, or the permission is wrong. 5xx mostly comes from the server or an intermediary, and here the codes emitted by Nginx or a gateway (413, 429, 502, 504) mean something quite different from the ones an application raises - conflating them sends the investigation in the opposite direction. This sheet walks 1xx through 5xx with meaning, typical cause and recommended handling, giving edge-proxy cases their own coverage, and focuses on the combinations most often mixed up: 401 means the server does not know who you are, 403 means it knows and refuses; 302 and 307 differ in whether a POST may be downgraded to GET; 502 means the backend returned something invalid or refused the connection, 504 means the backend accepted the connection and missed the deadline. The goal is that every code names its next action: which machine, which log, which setting.
Typical Use Case
When an integration request returns 500, start in the 5xx section to tell app-exception from gateway failure; a 401 means you first need a Token or login, while 403 means authenticated but not authorized, so check API permissions against the 4xx semantics; on Nginx 413/429, follow the code-level fix to raise the body limit or tune rate limiting; after reading, a bare status code tells you whether to check logs, change the request, or adjust server/gateway config.
1xx Informational 2
100 Continue101 Switching Protocols2xx Success 5
200 OK201 Created202 Accepted204 No Content206 Partial Content3xx Redirection 6
301 Moved Permanently302 Found303 See Other304 Not Modified307 Temporary Redirect308 Permanent Redirect4xx Client Error 17
400 Bad Request401 Unauthorized403 Forbidden404 Not Found405 Method Not Allowed406 Not Acceptable408 Request Timeout409 Conflict410 Gone413 Payload Too Large415 Unsupported Media Type418 I'm a teapot422 Unprocessable Entity426 Upgrade Required429 Too Many Requests431 Request Header Fields Too Large451 Unavailable For Legal Reasons5xx Server Error 8
500 Internal Server Error501 Not Implemented502 Bad Gateway503 Service Unavailable504 Gateway Timeout505 HTTP Version Not Supported507 Insufficient Storage511 Network Authentication RequiredParameter matrix
| Parameter | Effect | Example |
|---|---|---|
100 Continue | The client should go ahead and send its body, signalled as a pre-check before a large upload | |
101 Switching Protocols | Confirms a protocol switch; this is what a successful WebSocket upgrade returns | |
200 OK | The request succeeded: GET returns a resource, PUT and PATCH return the update result | |
201 Created | The resource was created; returned after POST with Location pointing at it | |
202 Accepted | Received but not yet processed, the code for async jobs and queued work | |
204 No Content | Successful with no body, the usual answer to DELETE | |
206 Partial Content | A range request succeeded; resumable downloads and video seeking depend on it | |
301 Moved Permanently | Permanent redirect that transfers SEO weight, the right code for HTTP to HTTPS | |
302 Found | Temporary redirect that transfers no weight and may turn a POST into a GET | |
303 See Other | Explicitly asks for a GET, the post-redirect-get pattern after a form submit | |
304 Not Modified | The resource is unchanged so the cached copy still applies; returned on a conditional request hit | |
307 / 308 | Redirect while preserving the request method, which matters when the POST must survive | |
400 Bad Request | The request is malformed: bad JSON or a missing required parameter | |
401 Unauthorized | Not authenticated: a missing or invalid token or cookie, so sign in first | |
403 Forbidden | Authenticated but not permitted: identity is fine, authorization is not | |
404 Not Found | The resource does not exist: wrong path or already deleted | |
405 Method Not Allowed | The method is not allowed, which is what a POST to a GET-only endpoint triggers | |
406 Not Acceptable | The Accept header cannot be satisfied and no negotiable format is available | |
408 / 429 | 408 means the client sent too slowly, 429 means the request rate hit the limiter | |
409 Conflict | The resource state conflicts, covering both duplicate creation and concurrent edits | |
410 Gone | Permanently removed, telling crawlers not to index more explicitly than 404 does | |
413 Payload Too Large | The body exceeds the limit, governed on the Nginx side by client_max_body_size | |
415 Unsupported Media Type | The Content-Type is unsupported, which is what a form post to a JSON endpoint triggers | |
422 Unprocessable Entity | Well-formed but semantically invalid, the right code for a failed field validation | |
426 / 431 | 426 demands a protocol upgrade, 431 means the headers themselves were too large | |
500 Internal Server Error | A server-side fault such as an exception or a null dereference; start with the application log | |
501 Not Implemented | The server does not support the method, the mirror of 405 with the fault on the server side | |
502 Bad Gateway | The gateway got an invalid upstream response, from a crash or a refused connection | |
503 Service Unavailable | Deliberately unavailable from overload, maintenance or throttling, with Retry-After giving the delay | |
504 Gateway Timeout | The gateway timed out waiting upstream, matching an exceeded proxy_read_timeout | |
505 / 507 / 511 | Unsupported protocol version, insufficient storage, and network authentication required |
Common pitfalls
SymptomThe browser console only shows a network error while the backend actually returned a 4xx.
CauseCross-origin failures hide both the body and the status from the browser, collapsing into one generic network error.
FixConfirm the real status with curl against the backend first, then review the CORS headers instead of diagnosing from what the browser showed.
SymptomEditing application code during a 5xx investigation changed nothing at all.
Cause502 and 504 usually originate between the gateway and the upstream on connect or wait timeouts, so the request never reached application code.
FixFirst confirm the application is really listening, then inspect gateway health checks and timeout settings; do not run that order backwards.
SymptomThe client treats a 301 as temporary and keeps a stale address in cache.
Cause301 is cached by browsers and every other client and carries the weight transfer, so once a URL is served as 301 the old hop keeps winning.
FixClear the cache before switching the origin URL, or use 302 as a temporary hop and only harden it once confirmed.
SymptomThe status in the gateway log does not match what the backend actually returned.
CauseA reverse proxy error page replaces the upstream status with its own, so the response you observe belongs to the proxy layer.
FixBypass the proxy error page while debugging, or use curl against the backend directly to confirm the status it returns itself.
SymptomUploads intermittently return 413 while smaller files go through.
CauseThe body exceeded the proxy layer ceiling and smaller files stayed under it; the limit lives in gateway configuration, not in the application.
FixRaise client_max_body_size on the Nginx side and confirm the application limit was widened to match.
SymptomThrottling misfires and returns 429 for traffic that is entirely normal.
CauseThe limiter keys on the wrong dimension, such as per IP when many users share one egress address, so healthy traffic lands in the same bucket.
FixReview the key dimension and split by user or endpoint path; check Retry-After first to confirm it really is throttling and not another 4xx.
SymptomThe retry logic waits a fixed amount while the server explicitly asked for longer.
CauseThe real backoff for 429 and 503 lives in the Retry-After header, and a hardcoded sleep overrides the cadence the server asked for.
FixMake the retry read Retry-After and wait accordingly instead of imposing a fixed value.
SymptomThe endpoint answers 200 for something that plainly failed.
CauseA 200 wrapping a business error leaves the HTTP layer unable to tell success from failure, so monitors and clients must parse the body to learn the outcome.
FixMap failures onto real status codes (401 for auth, 403 for permission, 400 or 422 for invalid input) and keep status and business code on separate layers.
SymptomAfter a form submit the browser issues another GET and the server sees entirely different fields.
CauseA 302 may rewrite the POST into a GET and drop the form data, whereas 303 explicitly asks for a GET.
FixUse 307 when the method must survive, and follow the PRG convention of 303 when redirecting after a form submit.
Troubleshooting
1Confirm the real status with curl instead of trusting the browser
curl -sI https://example.comThe first line is the real status; cross-origin failures collapse into a generic network error in the browser, and this surfaces the hidden 4xx.
2Emit status and elapsed time together for an observable probe
curl -s -o /dev/null -w '%{http_code} %{time_total}\n' https://example.comOne line is all that remains on screen, and the seconds value is directly usable as a latency alert threshold.
3Walk the redirect chain to confirm the final landing and every hop
curl -sIL https://example.comEach hop status is listed in order, which both exposes the difference between 301 and 302 and confirms you did not land on an interstitial.
4Count the 5xx spread in the server log to see which kind it is
grep -c '\" 50[0-9] ' /var/log/nginx/access.logA rising count means 5xx is happening; counting 502 and 504 separately then separates an invalid upstream response from an upstream wait timeout.
5Confirm whether throttling fired and how long to wait before retrying
curl -sI https://example.com | grep -i 'retry-after'Output means the server supplied a backoff duration that the retry logic should honour instead of a fixed sleep; no output means the 429 came from elsewhere.
Command Examples
Show only the HTTP status code of an API
curl -s -o /dev/null -w "%{http_code}\n" https://api.example.com/users/1This curl form discards the body and prints only the status: 200 for success, 404 for a wrong path, 401 for missing credentials, 500 for a server-side fault. One line is enough to decide whether an endpoint is alive.
Output
200
Count 5xx responses in the Nginx access log
awk '$9 ~ /^5[0-9][0-9]$/ {print $9}' /var/log/nginx/access.log | sort | uniq -cThe distinction matters: 502 means an upstream reply arrived but was unusable (a crashed backend or a refused connection), while 504 means the connection worked and the wait timed out. That tells you whether to inspect the backend process or to raise the proxy timeouts.
Output
3 502
5 504Check when to retry after a 429 rate-limit
curl -i https://api.example.com/search?q=laohandA 429 means the rate limit was hit. Read the Retry-After response header, which is in seconds, and wait that long before trying again; hammering the endpoint only escalates the limit or gets the client blocked.
Output
HTTP/1.1 429 Too Many Requests Retry-After: 120
Common Pitfalls
- Never bury business errors in 200: if the API signals failure via 200 + a body error code, clients cannot judge success from the status alone — an anti-pattern.
- 301 gets cached by browsers/clients: clear cache or use 302 before changing the origin URL, otherwise you keep seeing the old redirect.
- 400 vs 422 both mean a bad request: 400 is malformed syntax/structure, 422 is an invalid field value (semantic).
- Do not confuse 502 with 503: 502 means the gateway got an invalid upstream response, 503 means the service is actively down; mixing them misleads alerting.
- Check whether a proxy rewrote the response: Nginx default error pages can mask the real upstream status during debugging.
Tips
- 502 vs 504: 502 means the backend returned an invalid response (crash/refused); 504 means connected but timed out.
- 401 vs 403: 401 is 'who are you' (unauthenticated); 403 is 'you can't' (authenticated, no permission).
- Nginx 413: raise client_max_body_size; 429: check the limit_req rate-limiting config.
FAQ
What are the common HTTP status codes?
They group by the first digit: 1xx informational (100 Continue), 2xx success (200 OK, 201 Created), 3xx redirects (301 permanent, 302 found, 304 not modified), 4xx client errors (400/401/403/404/429) and 5xx server errors (500/502/503/504). This page lists 1xx–5xx with meaning, cause and a fix hint.
What is the difference between 401 and 403?
401 means unauthenticated — no valid credentials were presented, so login is required. 403 means authenticated but not authorized: identity is fine, but access to that resource is forbidden. Check login first, then permissions.
What is the difference between 301 and 302 redirects?
301 is permanent — browsers and search engines move ranking and bookmarks to the new URL. 302 is temporary — the original URL is kept. Use 301 for migrations, 302 for A/B tests or short-lived hops.
How do I tell whether a 4xx or 5xx error is my fault?
4xx points at the client — bad params, missing auth, no permission, wrong path — so inspect the request. 5xx points at the server — exceptions, timeouts, gateway 502/504 — so check server logs and dependencies.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us