HTTP status codes — every code, what it means, and the RFC it comes from
A complete list of HTTP status codes with the specification each one actually comes from. Most references still cite RFC 2616, retired in 2014; the core codes here are cited to RFC 9110, published June 2022, with WebDAV, RFC 6585 and RFC 7725 named where they apply. Non-standard codes from Cloudflare, nginx and IIS are listed separately and clearly labelled, never mixed in. Search the table, look up a code, and read the comparisons that decide which one you should be returning. Nothing is uploaded or saved.
- Nothing is uploaded or saved
- Works offline
Three digits, straight from your log line or your network tab.
Not Found
The server has no current representation for this URI and will not say whether it ever did or ever will.
1xx — Informational
The request was received and the process is continuing. A 1xx is an interim response: it is never the final answer, it carries no body, and older HTTP/1.0 clients are entitled to ignore it entirely. If you are debugging and see one, something else is still coming.
| Code | Name | Meaning | Defined by |
|---|---|---|---|
| 100 | Continuerare | The server has read the request headers, has not rejected the request, and the client should now send the body. It only ever appears in reply to a request carrying “Expect: 100-continue”.The point is to avoid uploading a large body to a server that was going to answer 401 or 413 anyway. | RFC 9110§15.2.1 |
| 101 | Switching Protocols | The server agrees to change protocol on this connection, as asked for in the Upgrade header. This is how a WebSocket handshake completes. | RFC 9110§15.2.2 |
| 102 | Processinghistorical | A WebDAV interim response meaning the server has accepted the request but has not finished, sent so the client does not time out.Removed from WebDAV when RFC 4918 replaced RFC 2518, but never deregistered. Treat it as obsolete. | RFC 2518 |
| 103 | Early Hintsrare | Sent before the real response so the browser can start fetching resources named in Link headers while the server is still assembling the page.Genuinely useful for preload and preconnect hints, and supported by the major browsers and CDNs — but still rarely deployed by ordinary applications. | RFC 8297 |
2xx — Successful
The request was received, understood and accepted. Which 2xx you pick matters more than it looks: 201 tells a client something now exists at a new URI, 204 tells a browser not to navigate away, and 206 is the whole basis of video seeking and resumable downloads.
| Code | Name | Meaning | Defined by |
|---|---|---|---|
| 200 | OK | The request succeeded, and the body is the result of it. | RFC 9110§15.3.1 |
| 201 | Created | The request succeeded and created one or more new resources. The Location header should give the URI of the primary one. | RFC 9110§15.3.2 |
| 202 | Acceptedrare | The request was accepted for processing, but nothing has happened yet and it may still fail. There is deliberately no promise about the outcome. | RFC 9110§15.3.3 |
| 203 | Non-Authoritative Informationrare | The response is a 200 that some proxy in the middle has modified. Rare, and easy to confuse with 200. | RFC 9110§15.3.4 |
| 204 | No Content | Success, and there is deliberately no body. Headers may still carry useful information. A browser will not navigate away on a 204. | RFC 9110§15.3.5 |
| 205 | Reset Contentrare | Success, no body, and the client should clear the form that produced the request so the user can enter another. | RFC 9110§15.3.6 |
| 206 | Partial Content | The server is returning only the byte ranges the client asked for in the Range header. Video seeking and resumable downloads run on this. | RFC 9110§15.3.7 |
| 207 | Multi-Statusrare | A WebDAV response whose XML body carries a separate status for each of several resources the one request touched. | RFC 4918§11.1 |
| 208 | Already Reportedrare | Inside a WebDAV 207 body, marks a collection whose members were already listed under an earlier binding, so they are not repeated. | RFC 5842§7.1 |
| 226 | IM Usedhistorical | The response is the result of applying one or more instance manipulations — delta encoding — to the current resource. | RFC 3229§10.4.1 |
3xx — Redirection
Further action is needed to complete the request, usually at the URI in the Location header. The five that matter differ on two questions only — is this permanent, and does the method survive — and getting that pair wrong is the single most common redirect bug.
| Code | Name | Meaning | Defined by |
|---|---|---|---|
| 300 | Multiple Choiceshistorical | The request has more than one possible response and the server is not choosing. There is no standard way to present the alternatives, which is why nothing uses it. | RFC 9110§15.4.1 |
| 301 | Moved Permanently | The resource has a new permanent URI, given in Location. Caches and search engines are expected to update their records.For historical reasons a user agent is allowed to change POST to GET when following it. If the method must survive, use 308. | RFC 9110§15.4.2 |
| 302 | Found | The resource is temporarily somewhere else. The original URI stays the one to use next time.Same historical POST-to-GET rewriting as 301. Use 307 if the method must survive, or 303 if you want the rewrite on purpose. | RFC 9110§15.4.3 |
| 303 | See Other | The result of this request is at another URI, and the client should fetch it with GET regardless of the method it just used.The correct answer to a successful POST when you want a refresh to reload the result page rather than re-submit the form. | RFC 9110§15.4.4 |
| 304 | Not Modified | The client’s cached copy is still current, so no body is sent. Answers a conditional request carrying If-None-Match or If-Modified-Since. | RFC 9110§15.4.5 |
| 305 | Use Proxyhistorical | Deprecated. It once told the client to reach the resource through a named proxy.Deprecated for security reasons; RFC 9110 says a client must not act on it. | RFC 9110§15.4.6 |
| 306 | (Unused)historical | Reserved. It was used in an early draft and is no longer assigned to anything. | RFC 9110§15.4.7 |
| 307 | Temporary Redirect | Like 302, but the method and the body must be kept exactly as they were when following it. | RFC 9110§15.4.8 |
| 308 | Permanent Redirect | Like 301, but the method and the body must be kept. This is the redirect to use for a permanently moved API endpoint.Originally defined in RFC 7538 and folded into RFC 9110. | RFC 9110§15.4.9 |
4xx — Client error
The request was faulty, or the client is not allowed to make it. “Client” means the caller, not necessarily a person doing something wrong: 404 and 429 are perfectly ordinary answers a healthy server gives all day. The rule is that repeating the identical request will not help until the client changes something.
| Code | Name | Meaning | Defined by |
|---|---|---|---|
| 400 | Bad Request | The server will not process the request because something about it is malformed — bad syntax, a framing error, deceptive routing.Not a general-purpose “something went wrong”. If the request was well formed and the problem is its content, 422 is the honest answer. | RFC 9110§15.5.1 |
| 401 | Unauthorized | The request lacks valid authentication for the target. The response must carry a WWW-Authenticate header naming a scheme the client can try.Misnamed: it means unauthenticated. “You are known and still not allowed” is 403. | RFC 9110§15.5.2 |
| 402 | Payment Requiredrare | Reserved for future use. There is no standard payment flow behind it.Some APIs use it for a quota or billing failure. That is a local convention, not a specification. | RFC 9110§15.5.3 |
| 403 | Forbidden | The server understood the request and refuses to authorise it. Sending different credentials will not help.A server may answer 404 instead when it does not want to admit the resource exists. That is explicitly allowed. | RFC 9110§15.5.4 |
| 404 | Not Found | The server has no current representation for this URI and will not say whether it ever did or ever will. | RFC 9110§15.5.5 |
| 405 | Method Not Allowed | The URI exists, but this method is not supported on it. The response must carry an Allow header listing the methods that are. | RFC 9110§15.5.6 |
| 406 | Not Acceptablerare | Nothing the server can produce matches the Accept headers the client sent.Most servers ignore the mismatch and send their default representation instead, which the spec permits. | RFC 9110§15.5.7 |
| 407 | Proxy Authentication Requiredrare | 401, but for the proxy rather than the origin server. Comes with Proxy-Authenticate instead of WWW-Authenticate. | RFC 9110§15.5.8 |
| 408 | Request Timeoutrare | The server closed an idle connection because the client did not produce a request in time.Often seen on a keep-alive connection the server reaped; the browser usually retries transparently. | RFC 9110§15.5.9 |
| 409 | Conflict | The request clashes with the current state of the resource — an edit against a version that has moved on, a duplicate unique key. | RFC 9110§15.5.10 |
| 410 | Gone | The resource was here, it is permanently gone, and no forwarding address exists. Stronger and more deliberate than 404. | RFC 9110§15.5.11 |
| 411 | Length Requiredrare | The server refuses the request because it has no Content-Length header. | RFC 9110§15.5.12 |
| 412 | Precondition Failedrare | A condition the client attached — If-Match, If-Unmodified-Since — was false when the server evaluated it.This is how optimistic locking is reported: your ETag no longer matches, so your update was not applied. | RFC 9110§15.5.13 |
| 413 | Content Too Large | The request body is larger than the server is willing or able to process.Renamed by RFC 9110; older documents call it “Payload Too Large” and RFC 2616 called it “Request Entity Too Large”. | RFC 9110§15.5.14 |
| 414 | URI Too Longrare | The request target is longer than the server is willing to interpret.Almost always a GET that should have been a POST, or a redirect loop appending a query parameter each time. | RFC 9110§15.5.15 |
| 415 | Unsupported Media Type | The body is in a format this resource does not accept.The usual cause is a missing or wrong Content-Type on a JSON request. | RFC 9110§15.5.16 |
| 416 | Range Not Satisfiablerare | None of the ranges asked for overlap the current size of the resource. | RFC 9110§15.5.17 |
| 417 | Expectation Failedrare | The expectation in the Expect header cannot be met by this server. | RFC 9110§15.5.18 |
| 418 | (Unused) — “I’m a Teapot”historical | Not a usable status. 418 comes from RFC 2324, the Hyper Text Coffee Pot Control Protocol, published on 1 April 1998 as a joke. IANA keeps 418 reserved so nobody can assign it to anything real.RFC 9110 §15.5.19 lists 418 as (Unused) for exactly this reason. Do not return it from a real service: proxies and clients have no defined behaviour for it. | RFC 2324§2.3.2 |
| 421 | Misdirected Requestrare | The request reached a server that is not configured to answer for this authority — a connection reused for a host it does not serve.Introduced by HTTP/2 (RFC 7540), where one connection can be reused across origins, and moved into RFC 9110. | RFC 9110§15.5.20 |
| 422 | Unprocessable Content | The syntax is fine and the content type is understood, but the content itself cannot be processed — validation failed.Started life in WebDAV (RFC 4918) as “Unprocessable Entity” and was adopted into core HTTP by RFC 9110 under the new name. | RFC 9110§15.5.21 |
| 423 | Lockedrare | The WebDAV resource, or its parent, is locked. | RFC 4918§11.3 |
| 424 | Failed Dependencyrare | The request failed because an earlier request it depended on failed, so this one was never attempted. | RFC 4918§11.4 |
| 425 | Too Earlyrare | The server will not risk processing a request replayed from TLS 1.3 early data, because a replay could be an attack. | RFC 8470§5.2 |
| 426 | Upgrade Requiredrare | The server refuses this request on the current protocol and names the required one in an Upgrade header. | RFC 9110§15.5.22 |
| 428 | Precondition Requiredrare | The server requires the request to be conditional, so that a lost-update race cannot happen silently. | RFC 6585§3 |
| 429 | Too Many Requests | The client has sent too many requests in a given period. A Retry-After header should say when to try again. | RFC 6585§4 |
| 431 | Request Header Fields Too Largerare | The headers are too big — either in total or one field on its own. An oversized cookie is the usual cause. | RFC 6585§5 |
| 451 | Unavailable For Legal Reasonsrare | Access is denied because of a legal demand — a court order, a takedown, a state block. The body should identify who made the demand.The number is a deliberate reference to Fahrenheit 451. It is a real, registered status all the same. | RFC 7725 |
5xx — Server error
The server knows it failed, or cannot do what was asked, and the request itself was fine. That distinction is the whole point of the class: a 5xx is an admission of fault, so returning one for bad user input sends your monitoring after a problem that does not exist.
| Code | Name | Meaning | Defined by |
|---|---|---|---|
| 500 | Internal Server Error | The server hit a condition it could not handle and has nothing more specific to say. The generic catch-all. | RFC 9110§15.6.1 |
| 501 | Not Implementedrare | The server does not support the functionality needed — for a method it does not recognise at all, rather than one it will not allow here.The difference from 405 is scope: 405 means “not on this resource”, 501 means “not by this server, on anything”. | RFC 9110§15.6.2 |
| 502 | Bad Gateway | A server acting as a gateway got an invalid response from the server upstream of it.Nearly always your reverse proxy telling you the application behind it crashed, or was never listening on the port the proxy expects. | RFC 9110§15.6.3 |
| 503 | Service Unavailable | The server cannot handle the request right now — overloaded, or deliberately down for maintenance. Retry-After can say for how long.The right status for planned maintenance: it tells search engines to come back rather than to drop the page. | RFC 9110§15.6.4 |
| 504 | Gateway Timeout | A gateway waited for the upstream server and gave up. The difference from 502 is that upstream answered nothing, rather than answering badly. | RFC 9110§15.6.5 |
| 505 | HTTP Version Not Supportedrare | The server refuses the major HTTP version used in the request. | RFC 9110§15.6.6 |
| 506 | Variant Also Negotiateshistorical | A transparent content-negotiation misconfiguration: the chosen variant is itself set up to negotiate, so the process cannot terminate. | RFC 2295§8.1 |
| 507 | Insufficient Storagerare | The WebDAV server cannot store what is needed to complete the request. | RFC 4918§11.5 |
| 508 | Loop Detectedrare | The server stopped an operation because it found an infinite loop while processing a WebDAV request with Depth: infinity. | RFC 5842§7.2 |
| 510 | Not Extended (obsoleted)historical | Meant to say that further extensions to the request were required. Its specification, the HTTP Extension Framework, has been moved to historic status.IANA marks this entry obsoleted. It should not be used in new work. | RFC 2774 |
| 511 | Network Authentication Requiredrare | The client must authenticate to get onto the network. Intended for captive portals, so that an intercepted response is not mistaken for the real site. | RFC 6585§6 |
Two questions separate all five, and most redirect bugs are one of them answered wrongly. Is the move permanent, and does the request method survive it? A 301 is allowed to turn your POST into a GET — which is exactly why a permanently moved API endpoint wants 308.
| Code | Name | Lifetime | Method | Reach for it when |
|---|---|---|---|---|
| 301 | Moved Permanently | Permanent | May change POST to GET | A page or a whole site that has moved for good. The one search engines act on. |
| 302 | Found | Temporary | May change POST to GET | A short-lived detour where the original URI stays canonical. Ambiguous on method — prefer 303 or 307 when a POST is involved. |
| 303 | See Other | Temporary | Always becomes GET | After a successful POST, to send the browser to a result page a refresh can safely reload. |
| 307 | Temporary Redirect | Temporary | Preserved, body and all | A temporary move where a POST must arrive at the new URI still a POST. |
| 308 | Permanent Redirect | Permanent | Preserved, body and all | A permanently moved API endpoint. 301 would risk turning your POST into a GET. |
None of these are HTTP status codes in the standards sense. Each is emitted by one particular piece of software and means whatever that software says it means. They are here because you will meet them in logs and need to look them up — never because your own service should return one. Nothing outside the originating software knows what they are.
Cloudflare
A 5xx in this range comes from Cloudflare’s edge, not from your server — your server usually never saw the request. The number tells you which leg of the connection failed.
| 520 | Web Server Returned an Unknown Error | The origin returned something empty, unexpected or malformed that Cloudflare could not turn into a valid HTTP response. The catch-all of this range. |
| 521 | Web Server Is Down | The origin refused the connection outright — nothing is listening, or a firewall is blocking Cloudflare’s IP ranges. |
| 522 | Connection Timed Out | The TCP handshake to the origin did not complete in time. Usually a firewall dropping packets silently rather than rejecting them. |
| 523 | Origin Is Unreachable | Cloudflare could not route to the origin at all — commonly a DNS record pointing at an address that no longer exists. |
| 524 | A Timeout Occurred | The connection succeeded but the origin did not finish its response inside Cloudflare’s time limit. A slow query, not a down server. |
| 525 | SSL Handshake Failed | The TLS handshake between Cloudflare and the origin failed — mismatched cipher suites, or no valid certificate on the origin. |
| 526 | Invalid SSL Certificate | The origin presented a certificate Cloudflare could not validate, while the zone is set to a strict SSL mode that requires a valid one. |
| 527 | Railgun Error | A failure between Cloudflare and a Railgun listener. Railgun has been retired, so this is now historical. |
| 530 | Site Frozen / paired error | Always accompanied by a Cloudflare 1xxx error code shown in the body; the 1xxx number is the one that tells you what actually happened. |
nginx
These never travel over the wire as a status line — nginx writes them to its own access log to record how a connection ended. Searching for one in a log is the only way you will meet them.
| 444 | No Response | nginx closed the connection without sending anything at all. It is what the “return 444;” directive does, usually to drop unwanted traffic cheaply. |
| 494 | Request header too large | The request headers exceeded large_client_header_buffers. Logged internally; the client sees 400. |
| 495 | SSL Certificate Error | Client certificate verification failed during a mutual-TLS handshake. |
| 496 | SSL Certificate Required | The client presented no certificate where the configuration required one. |
| 497 | HTTP Request Sent to HTTPS Port | A plain HTTP request arrived on a port configured for TLS. |
| 499 | Client Closed Request | The client disconnected before nginx could answer. A burst of these usually means your upstream is slow enough that users are giving up, not that anything is broken in nginx. |
IIS sub-status codes
IIS appends a decimal sub-code to a normal status — 401.3, 404.13 — in its logs and on its own error pages. The client still receives the plain status; the fraction is for you, and it is the part that names the actual cause.
| 401.1 | Logon failed | The credentials supplied were rejected at logon. |
| 401.2 | Logon failed due to server configuration | The authentication method the client used is not enabled on the server. |
| 401.3 | Unauthorized due to ACL on resource | Windows file-system permissions denied access to the file itself. |
| 403.4 | SSL required | The resource is configured to require HTTPS and the request arrived over HTTP. |
| 403.14 | Directory listing denied | No default document exists and directory browsing is switched off. |
| 404.4 | No handler configured | No handler mapping matches the requested extension. |
| 404.13 | Content length too large | The request body exceeded maxAllowedContentLength — the IIS-level limit, which is separate from your application’s. |
| 500.19 | Configuration data is invalid | web.config could not be read or contains a section the server will not accept. |
| 500.30 | ASP.NET Core app failed to start | The ASP.NET Core Module started the process and it exited before it began listening. |
Other servers
One more that turns up often enough in shared-hosting logs to be worth naming. Codes such as 420 and 598 are frequently listed elsewhere as non-standard statuses; they are left out here because their definitions could not be pinned to a source that still publishes them.
| 509 | Bandwidth Limit Exceeded | Emitted by an Apache bandwidth-limiting module and by cPanel when an account passes its monthly transfer allowance. Never registered with IANA. |
How it works
- 1
Find the code you are holding
Type a number into the lookup and you get that code alone: its reason phrase, what it means in a sentence, the RFC and section that define it, and whether it is something you will meet in practice or a historical curiosity. Three digits is usually all you have when a log line hands you one.
- 2
Or search by what you are trying to say
The filter runs over the name, the meaning and the notes, not just the number. Searching “redirect”, “cache”, “rate limit” or “authentication” narrows the table to the codes that concern it, which is the more common direction — you know the situation and you want the right code for it.
- 3
Read the class before the code
Each of the five classes carries a real explanation, because the class is doing most of the work. A 4xx says the caller must change something before retrying; a 5xx is the server admitting fault. Returning 500 for bad user input is not a cosmetic mistake — it sends your on-call after a problem that does not exist.
- 4
Settle the four redirects with the table, not from memory
Two questions separate 301, 302, 303, 307 and 308: is the move permanent, and does the method survive it. The matrix answers both for all five at once. A 301 is allowed to turn your POST into a GET, which is why a permanently moved API endpoint wants 308 instead.
- 5
Check the non-standard section separately
Cloudflare’s 520–527, nginx’s 444 and 499, and the IIS sub-codes such as 404.13 are in their own section with the software that emits each one named. They are worth looking up and must never be returned by your own service — nothing outside their originating software knows what they mean.
Frequently asked questions
Which RFC should I be citing in 2026?
RFC 9110, HTTP Semantics, published June 2022. It replaced RFC 7230 through 7235, which had themselves replaced RFC 2616 back in 2014, and it is where the status code registry now points for the core codes. It also absorbed three codes that used to live elsewhere: 308 came from RFC 7538, 421 from RFC 7540 (HTTP/2), and 422 from WebDAV’s RFC 4918, renamed from “Unprocessable Entity” to “Unprocessable Content”. Not everything moved, though, which is why this table cites per code rather than putting one RFC in a footer: 429 is RFC 6585, 451 is RFC 7725, and 423, 424 and 507 are still RFC 4918.
Is 418 I’m a Teapot real?
It is a real registration and not a real status. It comes from RFC 2324, the Hyper Text Coffee Pot Control Protocol, published on 1 April 1998 as a joke. RFC 9110 lists 418 as “(Unused)” and IANA keeps it reserved specifically so it can never be assigned to something serious. So you can look it up and you should not return it: no proxy, cache or client library has any defined behaviour for it, and “our API answers 418” is a support ticket waiting to be filed.
What is the difference between 301, 302, 307 and 308?
Two independent questions. Permanence: 301 and 308 say the resource has moved for good and caches and search engines should update; 302, 303 and 307 say it is temporary and the original URI stays canonical. Method: 307 and 308 require the method and body to be preserved exactly, 303 always turns the follow-up into a GET, and 301 and 302 sit in the middle — for historical reasons a user agent is permitted to rewrite POST to GET, and in practice they do. So a permanently moved API endpoint wants 308, not 301; a temporarily moved one wants 307; and the redirect after a successful form POST wants 303, so that pressing refresh reloads the result page instead of re-submitting the form.
When should I use 401 and when 403?
401 means unauthenticated, despite being named “Unauthorized”. It says the request carried no valid credentials and the response must include a WWW-Authenticate header naming a scheme the client can try — sending different credentials might work. 403 means authenticated and still refused: the server understood who you are and will not do it, so retrying with other credentials will not help. The everyday test is whether logging in as someone else could change the answer. There is also a legitimate third option: a server is explicitly allowed to answer 404 instead of 403 when admitting the resource exists would itself leak something.
Should a deleted page return 404 or 410?
410 when you are certain it is gone for good and there is no forwarding address; 404 when you are not, or when you simply do not know. 410 is the stronger statement — “this was here, it has been removed, stop asking” — and crawlers treat it as more decisive than a 404, which they will re-check for a while in case it was a mistake. The practical difference is small enough that it is not worth agonising over: both remove a page from a search index eventually, and neither is a substitute for a 301 to the page that replaced it.
What should a 429 actually include?
A Retry-After header, and a body that explains the limit. Retry-After takes either a number of seconds or an HTTP-date, and without it the client is left guessing — which in practice means retrying immediately and making your overload worse. RFC 6585 defines the code and recommends the body describe the limit; the widely used RateLimit header fields for the remaining quota are a separate, later specification and are not part of it. Note also that 429 is about the client’s rate, while 503 is about your capacity: use 503 with Retry-After when everyone is affected.
Why do I get a 502 or 504 when my server looks fine?
Because neither comes from your application — both come from something in front of it. 502 Bad Gateway means the reverse proxy reached your service and got back something it could not parse as an HTTP response, which usually means the process crashed mid-request or nothing is listening on the port the proxy is configured for. 504 Gateway Timeout means the proxy connected fine and gave up waiting, so your code is running and simply slow. That distinction is the fastest triage available: 502 points at the process, 504 points at a query.
What are Cloudflare’s 5xx codes and why are they separate here?
Because they are not HTTP status codes in the standards sense at all — they are Cloudflare’s own numbers in the 520–527 range, returned by its edge to tell you which leg of the connection to your origin failed. 521 means your server refused the connection, 522 means the TCP handshake timed out (usually a firewall dropping Cloudflare’s IP ranges silently), 524 means the connection worked and your server did not finish in time, and 525 and 526 are TLS problems between the edge and the origin. Mixing them into the IANA table would make this page lie about the one thing it is for. The same applies to nginx’s 444 and 499, which never travel over the wire at all — nginx writes them into its own access log to record how a connection ended.
Does anything I type into the lookup leave my browser?
No. The whole registry is part of the JavaScript this page already loaded, so both the search and the lookup are running over an array in memory. There is no API call behind them, nothing is written to localStorage, and the page keeps working with the network switched off.