Quick answer
HTTP status codes are the three-digit numbers a server puts at the start of every response to say how the request went: 1xx informational, 2xx success, 3xx redirection, 4xx client error and 5xx server error. The number does not say which machine wrote it. A 4xx or 5xx can come from the application, a reverse proxy, or a CDN or WAF in front of both, and some codes may be cached and replayed to other visitors.
01What are HTTP status codes?
Every HTTP response begins with a status code, an integer from 100 to 599 that describes the result of the request. In RFC 9110, the current definition of HTTP semantics, the first digit sets the class and the other two carry no category. The text after the number, such as Not Found, is only a recommended reason phrase. How requests and responses are structured is covered in what HTTP is; this page is the reference for the codes.
Clients do not have to know every code. The specification requires them to understand the class and to treat an unrecognised code as the x00 code of that class, so an unknown 471 is handled like a 400. A value outside 100 to 599 is invalid and should be treated as a server error.
- 1xx Informational: an interim response, such as 100 Continue or 103 Early Hints, before the final one
- 2xx Successful: the request was received, understood and accepted
- 3xx Redirection: the client must take a further step, usually by following the Location header
- 4xx Client error: the request was wrong or cannot be fulfilled as sent, so repeating it unchanged usually fails again
- 5xx Server error: the server, or something in front of it, failed to handle a request that looked valid
02HTTP status codes list: meaning, sender and caching
The table covers the codes you will meet in practice. "Usually sent by" is the layer that most often writes the code on a typical site with a CDN or WAF, a reverse proxy and an application; any layer can technically send any code. "Cacheable by default" follows RFC 9110 and RFC 9111: those codes may be stored and reused without explicit freshness headers, while every other code needs Cache-Control or Expires before a cache may keep it.
| Code | Meaning | Usually sent by | Cacheable by default | Header to look for |
|---|---|---|---|---|
| 100 Continue | Go ahead and send the request body | Origin or proxy | No (interim) | Request had Expect: 100-continue |
| 101 Switching Protocols | Protocol change accepted, e.g. WebSocket | Origin | No (interim) | Upgrade |
| 103 Early Hints | Preload hints before the final response | Origin or CDN | No (interim) | Link |
| 200 OK | Success | Origin or a cache | Yes | Age, if a cache served it |
| 201 Created | A new resource was created | Application (API) | No | Location |
| 202 Accepted | Queued, not yet processed | Application (API) | No | Body points to a status URL |
| 204 No Content | Success, deliberately empty body | Origin | Yes | No body at all |
| 206 Partial Content | Part of a file, for a Range request | Origin or a cache | Yes | Content-Range |
| 301 Moved Permanently | Permanent redirect | Origin or a CDN redirect rule | Yes | Location |
| 302 Found | Temporary redirect | Origin or application | No | Location |
| 304 Not Modified | The cached copy is still valid | Origin or a cache | Refreshes the stored copy | ETag or Last-Modified, no body |
| 307 Temporary Redirect | Temporary redirect, same method | Origin, or the browser for HSTS | No | Location |
| 308 Permanent Redirect | Permanent redirect, same method | Origin or a CDN redirect rule | Yes | Location |
| 400 Bad Request | Malformed or unacceptable request | Any layer, often a proxy | No | Server names the layer |
| 401 Unauthorized | Missing or rejected credentials | Application or an auth proxy | No | WWW-Authenticate (required) |
| 403 Forbidden | Understood, but refused | Origin, WAF or CDN | No | Branded block page |
| 404 Not Found | Nothing at this URL | Origin | Yes | None |
| 405 Method Not Allowed | Method not supported for this URL | Origin | Yes | Allow (required) |
| 407 Proxy Authentication Required | A forward proxy wants credentials | Corporate or forward proxy | No | Proxy-Authenticate (required) |
| 408 Request Timeout | Request not completed in time | Server or proxy | No | Connection: close |
| 409 Conflict | Clashes with the resource's current state | Application | No | None |
| 410 Gone | Removed on purpose, for good | Origin | Yes | None |
| 413 Content Too Large | Request body too big | Proxy or origin | No | Retry-After, if temporary |
| 414 URI Too Long | URL too long | Proxy or origin | Yes | None |
| 422 Unprocessable Content | Well-formed, but fails validation | Application (API) | No | None |
| 429 Too Many Requests | Rate limit reached | Rate limiter at the edge, proxy or app | Must not be stored | Retry-After (optional) |
| 431 Request Header Fields Too Large | Headers or cookies too big | Runtimes such as Node.js or Go | Must not be stored | None |
| 500 Internal Server Error | Unhandled application error | Application | No | None |
| 501 Not Implemented | Method not supported at all | Origin or proxy | Yes | None |
| 502 Bad Gateway | Invalid or no answer from upstream | Proxy or CDN | No | Server of the proxy |
| 503 Service Unavailable | Temporarily unable to serve | Proxy or origin | No | Retry-After (optional) |
| 504 Gateway Timeout | Upstream did not answer in time | Proxy or CDN | No | Server of the proxy |
03How do you tell who generated a status code?
Find the author before debugging, because the same number means different things at different layers. A 403 from a web application firewall is a blocked request; a 403 from the application is a permission check. The Server header usually names the software that wrote the response, proxies add a Via header, CDNs add their own (Cloudflare adds CF-Ray, for example), and an Age header shows the response came out of a cache.
Then compare two requests: one through the public hostname, one straight to the origin with the same hostname and TLS server name. If only the first fails, the edge, or something between it and the origin, wrote the error.
The browser can produce a status too. A 301 it cached earlier is replayed without contacting the server, and on a site that uses HSTS the browser rewrites http:// to https:// before sending anything, which Chrome's developer tools show as a 307 Internal Redirect. Some failures carry no status code at all because no HTTP response arrived: this site can't be reached means DNS or the connection failed, ERR_SSL_PROTOCOL_ERROR means the TLS handshake failed, and ERR_TOO_MANY_REDIRECTS means a redirect loop.
Logs also show unregistered codes: nginx uses 444 to close a connection without a response and logs 499 when the client hung up first, and several CDNs define their own 5xx codes, such as the Cloudflare error codes 520 to 530.
# through the CDN or proxy: the status line and the headers that name the author
curl -s -o /dev/null -D - https://example.com/page | grep -iE '^(HTTP|server|via|age|x-cache|cf-ray)'
# straight to the origin, with the same Host header and TLS server name
curl -s -o /dev/null -D - --resolve example.com:443:203.0.113.10 https://example.com/page | grep -iE '^(HTTP|server|via|age)'04Which HTTP status codes can be cached?
A shared cache such as a CDN may store a response only when permitted. RFC 9111 allows it when the response carries explicit freshness (Cache-Control with max-age or s-maxage, or an Expires header), a public directive, or a status code defined as heuristically cacheable. In RFC 9110 those codes are 200, 203, 204, 206, 300, 301, 308, 404, 405, 410, 414 and 501. Everything else, including 302, 307, 401, 403, 500 and 503, is stored only when headers explicitly allow it.
Heuristic freshness is a guess, and RFC 9111 suggests 10% of the time since Last-Modified as a typical setting. Worked example: a page last modified 10 days ago and sent with no Cache-Control may be treated as fresh for about a day, because 10% of 240 hours is 24 hours. That is how a 404 or 301 sent without cache headers can keep being served after you have fixed the page.
Four codes are never stored: RFC 6585 says responses with 428, 429, 431 and 511 must not be stored by a cache. And a shared cache must not reuse a response to a request that carried an Authorization header unless the response explicitly allows it, which matters for 401 errors behind a proxy.
052xx success codes: 200, 201, 202 and 204
200 OK is the ordinary success response; its body depends on the method.
201 Created means the request created at least one new resource, typically after a POST or PUT to an API. RFC 9110 identifies the new resource by the Location header or, if that is missing, by the request URL, so an API that answers 201 should send something like Location: /orders/1234 instead of leaving the client to guess.
202 Accepted means the request was queued but not yet processed, and it may still fail later. It suits slow work such as exports or video encoding: the server answers at once, and the body should describe the job and point to a status URL the client can poll. HTTP has no way to deliver the final status of a 202 afterwards, so that URL is the only channel.
204 No Content is success with a deliberately empty body, common for DELETE requests. 206 Partial Content answers a Range request, which is how video players fetch a file in pieces.
063xx redirects in brief
Five codes do most redirecting. 301 and 308 are permanent and cacheable by default; 302 and 307 are temporary; 303 sends the client to a different resource with GET, the usual answer after a form submission. 307 and 308 forbid the client from changing the request method, whereas for historical reasons a browser may turn a POST into a GET after a 301 or 302. Choosing between all five deserves its own comparison, and a redirect that points back at itself ends in too many redirects.
304 Not Modified is formally a redirect too, to the copy the client already holds: the client asked conditionally, with If-None-Match or If-Modified-Since, and the server confirms that its stored version is still valid.
07Which status codes should an API return?
Clients branch on the status code before they read the body, so choose the code that tells them what to do next.
For the body, RFC 9457 defines Problem Details, a standard JSON shape served as application/problem+json. Its members type, title, status, detail and instance give every error one format, and an API may add fields of its own.
| Situation | Status code | What the client should do |
|---|---|---|
| Body is not valid JSON, or a required field is missing | 400 Bad Request | Fix the request; resending it unchanged fails again |
| Well-formed, but fails validation rules | 422 Unprocessable Content | Show the field errors to the user |
| No token, or an expired or invalid one | 401 Unauthorized, with WWW-Authenticate | Obtain or refresh credentials |
| Valid token without the needed permission | 403 Forbidden | Do not retry with the same token |
| Resource does not exist, or must stay hidden | 404 Not Found | Check the identifier |
| Conflicting state, such as a version mismatch | 409 Conflict | Re-read the resource, then retry |
| Client exceeded its quota | 429 Too Many Requests, with Retry-After | Wait, then retry with backoff |
| Unexpected failure inside the API | 500 Internal Server Error | Retry later, only if the call is safe to repeat |
| Dependency down or capacity exhausted | 503 Service Unavailable, with Retry-After | Retry after the stated delay |
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
{
"type": "https://example.com/problems/invalid-email",
"title": "The email address is not valid",
"status": 422,
"detail": "'bob@' has no domain part",
"instance": "/signups/7c1e"
}08How do status codes affect search engines?
Google documents that its crawlers treat every 4xx code except 429 the same way, as content that does not exist, and that those codes have no effect on crawl rate. 5xx codes and 429 make the crawlers slow down for a while, and URLs that keep returning server errors are eventually dropped from the index. A 401 or 403 therefore cannot slow Googlebot down.
So an HTTP flood that exhausts the origin is a search problem too: crawlers see the 5xx responses it causes.
Questions
Frequently asked questions
Sources
Sources and verification
The header checks were run with curl 7.88.1 against a public example host, and the Problem Details body was parsed with the json module of Python 3.11. Debian 12, October 2026.
- 01RFC 9110, HTTP Semantics, section 15: Status Codes · RFC Editor
- 02RFC 9111, HTTP Caching, section 4.2.2: Calculating Heuristic Freshness · RFC Editor
- 03RFC 6585, Additional HTTP Status Codes (428, 429, 431, 511) · RFC Editor
- 04Hypertext Transfer Protocol (HTTP) Status Code Registry · IANA
- 05RFC 9457, Problem Details for HTTP APIs · RFC Editor
- 06RFC 6797, HTTP Strict Transport Security, section 8.3 · RFC Editor
- 07How HTTP status codes affect Google's crawlers · Google Search Central
- 08Module ngx_http_rewrite_module: return (code 444) · nginx.org
- 09nginx source: ngx_http_request.h (codes 444 and 494 to 499) · nginx on GitHub
- 10Cloudflare HTTP headers (CF-Ray) · Cloudflare docs
Last updated