🌐 HTTP Status Codes Reference

Every HTTP status code you'll meet β€” standard, de facto, and common non-standard β€” with what it means, when to send it, and the 2026 adoption notes. Jump by class or Ctrl+F for a specific number.

Updated October 2026 Β· based on RFC 9110 (2022) + ongoing IANA registry.

Jump to class

πŸ“¨ 1xx β€” Informational provisional

The server is telling the client "I've seen your request, keep going". Final response will come separately. 103 is the big modern one β€” used by Cloudflare and Fastly for preloading since 2023, now common in production.

CodeNameWhen to use
100ContinueClient sent Expect: 100-continue and should keep sending the body.
101Switching ProtocolsResponse to Upgrade:, used by WebSockets.
102Processing (WebDAV)Request is being processed, no response yet. Rarely seen outside WebDAV.
103Early HintsPreload hints before the real response. Big LCP win if your CDN supports it (Cloudflare, Fastly, Chrome 103+).

βœ… 2xx β€” Success it worked

CodeNameWhen to use
200OKDefault success. GET returns the resource; POST returns the result.
201CreatedPOST/PUT created a new resource. Include Location: header.
202AcceptedRequest accepted but not processed yet (async job).
203Non-Authoritative InformationReturned content was modified by a proxy. Rare in practice.
204No ContentSuccess with no body β€” common for PUT/DELETE, or empty API responses.
205Reset ContentTells the client to reset the form that triggered the request. Barely used.
206Partial ContentResponse to a Range: request (video streaming, resumable downloads).
207Multi-Status (WebDAV)XML body with per-resource statuses.
208Already Reported (WebDAV)Member of a bound collection, already enumerated.
226IM UsedDelta encoding; essentially a museum piece.

β†ͺ️ 3xx β€” Redirection go somewhere else

CodeNameWhen to use
300Multiple ChoicesServer offers several representations; client picks. Essentially unused.
301Moved PermanentlyPermanent redirect. Cached hard β€” hard to undo. Use for domain/URL rename.
302FoundTemporary redirect. Historically ambiguous on method change; most clients convert POST→GET.
303See OtherAfter a POST, redirect to a GET. The modern "POST-redirect-GET" pattern.
304Not ModifiedConditional GET matched If-Modified-Since or If-None-Match. No body.
305Use ProxyDeprecated β€” browsers refuse it for security.
307Temporary RedirectLike 302 but method is preserved. POST stays POST.
308Permanent RedirectLike 301 but method is preserved. Modern replacement for 301.
Permanent vs temporary matters for SEO: 301/308 transfer link juice to the new URL. 302/307 don't β€” the search engine keeps indexing the old one.

❌ 4xx β€” Client errors your fault

CodeNameWhen to use
400Bad RequestMalformed request β€” bad JSON, bad params. Default for client-side errors you can't categorize.
401UnauthorizedCredentials required and missing/invalid. Must include WWW-Authenticate header. (Actually means "unauthenticated".)
402Payment RequiredReserved. Stripe/Lemon Squeezy sometimes use it for "upgrade your plan".
403ForbiddenAuthenticated but not allowed. Correct code for "logged in but can't access this".
404Not FoundResource doesn't exist. Can also mean "exists but you can't know" (avoids leaking info).
405Method Not AllowedGET on a POST-only endpoint, etc. Must include Allow: header listing valid methods.
406Not AcceptableServer can't match Accept: header. Rare.
407Proxy Authentication RequiredLike 401 but for a proxy.
408Request TimeoutClient took too long sending the request.
409ConflictRequest conflicts with current state β€” edit conflict, duplicate key.
410GoneResource used to exist, now permanently removed. Strongly cached. Signals to Google to deindex faster than 404.
411Length RequiredRequest lacks Content-Length.
412Precondition FailedA conditional header (If-Match, etc) didn't match. Use for optimistic concurrency.
413Content Too LargeRequest body exceeds server limit. (Was "Payload Too Large".)
414URI Too LongUsually seen with runaway GET-with-many-params.
415Unsupported Media TypeServer doesn't accept the Content-Type.
416Range Not SatisfiableClient asked for a byte range outside the resource.
417Expectation FailedServer can't satisfy the Expect: header.
418I'm a teapotJoke RFC. Returned by actual teapots and some error pages. Not for serious use.
421Misdirected RequestRequest was routed to a server that can't produce a response. HTTP/2 connection reuse edge case.
422Unprocessable ContentRequest is well-formed but semantically invalid. Classic for validation failures.
423Locked (WebDAV)Resource is locked.
424Failed Dependency (WebDAV)Previous request in a sequence failed.
425Too EarlyServer unwilling to risk processing an early-data request (TLS 1.3 0-RTT).
426Upgrade RequiredClient should switch protocols (e.g., to TLS). Include Upgrade: header.
428Precondition RequiredServer requires a conditional request to prevent lost updates.
429Too Many RequestsRate limiting. Include Retry-After:.
431Request Header Fields Too LargeHeaders (cumulative or single) exceed server limit.
451Unavailable For Legal ReasonsGDPR removal, DMCA takedown, government censorship. The "451" is a nod to Fahrenheit 451.
400 vs 422: 400 = can't parse the request. 422 = parsed fine but failed business validation. A lot of APIs use 400 for both; 422 is more precise.

πŸ’₯ 5xx β€” Server errors our fault

CodeNameWhen to use
500Internal Server ErrorCatch-all for unhandled server exceptions. Should be rare and alertable.
501Not ImplementedMethod or feature isn't supported. Different from 405: 405 = known endpoint, wrong method; 501 = method unknown to server.
502Bad GatewayUpstream (origin, app server) returned garbage or died.
503Service UnavailableTemporarily down β€” maintenance, overloaded. Include Retry-After:.
504Gateway TimeoutUpstream didn't respond in time.
505HTTP Version Not SupportedClient used an HTTP version the server refuses.
506Variant Also NegotiatesContent negotiation misconfiguration. Rare.
507Insufficient Storage (WebDAV)Can't store the submitted representation.
508Loop Detected (WebDAV)Infinite loop processing the request.
510Not ExtendedServer needs an HTTP extension the client didn't declare. Essentially unused.
511Network Authentication RequiredCaptive portals ("sign in to Wi-Fi"). Should include a login URL.

🧩 Non-standard β€” Cloudflare, nginx, IIS

CodeSourceMeans
444nginxConnection closed without a response. Used to drop bad clients.
494nginxRequest header too large.
495nginxSSL certificate error.
496nginxSSL certificate required but not provided.
497nginxHTTP sent to HTTPS port.
499nginxClient closed the connection before the server responded.
520CloudflareUnknown error from the origin.
521CloudflareOrigin web server refused the connection.
522CloudflareConnection to origin timed out.
523CloudflareOrigin unreachable (routing issue).
524CloudflareA timeout occurred reading from origin.
525CloudflareSSL handshake with origin failed.
526CloudflareOrigin SSL certificate invalid.
530CloudflareError on Cloudflare's side. Often paired with another 5xx in the body.

🎯 Picking the right code β€” common dilemmas

User isn't logged in

401, not 403. 401 means "no credentials or bad credentials β€” try again". Must include WWW-Authenticate header.

User is logged in but not allowed

403, not 401. Resending the same credentials won't help.

Resource doesn't exist OR user can't see it

If leaking "exists" is sensitive (private repo, invite-only post), return 404 for both. Otherwise 404 vs 403 is a UX choice.

Validation failed

422 is the precise code. 400 is widely accepted but less specific. Pick one convention per API and stick to it.

Rate limiting

429 with Retry-After: <seconds>. Include a JSON body explaining which limit was hit if you can.

Legal takedown

451 is the correct code. Google will treat it differently from 404 for crawl purposes.

Maintenance window

503 with Retry-After:. Google won't deindex a page returning 503 for a short time, but it will if you leave it there for days.

URL moved to a new one

308 if permanent (preserves POST/PUT bodies). 307 if temporary. Use 301/302 only if you need to interoperate with ancient clients.

POST β†’ redirect to GET

303 See Other. Classic "Post-Redirect-Get" pattern β€” prevents accidental re-submits on refresh.

🧰 Related tools