Tutorial

HTTP Status Codes Explained: What 301, 403, 404, 500, 502, and 503 Mean

March 31, 2026

Back to Blog

Every time your browser loads a web page, makes an API call, or downloads a file, the server responds with an HTTP status code — a three-digit number that tells the client exactly what happened with the request. Understanding these codes is fundamental to web development, server administration, and debugging. When something goes wrong, the status code is your first clue.

This guide covers the most important HTTP status codes you will encounter in practice, what causes each one, and concrete steps to fix them when they indicate a problem.

The Five Categories

HTTP status codes are organized into five classes based on the first digit. Each class represents a fundamentally different type of response.

RangeCategoryMeaningWho Needs to Act
1xxInformationalRequest received, processing continuesNo one (automatic)
2xxSuccessRequest was received, understood, and acceptedNo one (all good)
3xxRedirectionFurther action needed to complete the requestClient follows redirect
4xxClient ErrorThe request contains bad syntax or cannot be fulfilledClient (fix the request)
5xxServer ErrorThe server failed to fulfill a valid requestServer admin (fix the server)

2xx Success Codes

200 OK

The most common status code. The request succeeded, and the response body contains the requested resource. For a GET request, this means the resource was found and returned. For a POST request, this means the action was completed successfully.

$ curl -I https://example.com
HTTP/2 200
content-type: text/html; charset=UTF-8

201 Created

The request succeeded and a new resource was created. Typically returned by POST requests when creating a new database record, user account, or file. The response usually includes a Location header pointing to the newly created resource.

$ curl -X POST -d '{"name":"New Item"}' https://api.example.com/items
HTTP/2 201
Location: /items/42

204 No Content

The request succeeded, but there is no content to return. Common for DELETE requests (the resource was deleted successfully) and PUT/PATCH requests where the server does not need to return the updated resource.

3xx Redirection Codes

301 Moved Permanently

The resource has been permanently moved to a new URL. The client (and search engines) should update their bookmarks and links. This is the code to use when you change a URL structure, migrate to a new domain, or enforce HTTPS.

SEO Impact: Search engines transfer link equity ("link juice") from the old URL to the new one. This is the recommended redirect for SEO when you need to change URLs permanently.

# Nginx: Redirect HTTP to HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}

302 Found (Temporary Redirect)

The resource is temporarily located at a different URL. The client should continue using the original URL for future requests. Use this for maintenance pages, A/B testing, or temporary redirects.

SEO Impact: Search engines do not transfer link equity. They keep the original URL in their index.

304 Not Modified

The resource has not changed since the last request. The client can use its cached version. This is an optimization — instead of re-downloading the same content, the server tells the browser "your cache is still valid." You will see this frequently in browser DevTools for static assets like CSS, JavaScript, and images.

4xx Client Error Codes

Client errors indicate that the problem is with the request itself — wrong URL, missing authentication, forbidden access, or invalid data.

400 Bad Request

The server cannot process the request because it is malformed. This could be invalid JSON in the request body, missing required parameters, invalid URL encoding, or a request that violates the protocol.

Common Causes:

  • Malformed JSON in a POST/PUT request body
  • Missing required query parameters or headers
  • Request body exceeds the expected format
  • Invalid characters in the URL
  • Cookie data that is too large or corrupted

How to Fix: Check the request body for valid JSON, verify all required parameters are included, and examine the response body for specific error messages.

401 Unauthorized

The request requires authentication, and either no credentials were provided or the credentials are invalid. Despite the name "Unauthorized," this code actually means "Unauthenticated" — the server does not know who you are.

Common Causes:

  • Missing or expired JWT token
  • Invalid API key
  • Expired session cookie
  • Wrong username or password in Basic Auth

How to Fix: Ensure your authentication token or credentials are valid and included in the request. For JWT, check if the token has expired. For API keys, verify the key is correct and active.

403 Forbidden

The server understood the request and the client is authenticated, but the client does not have permission to access the resource. Unlike 401, re-authenticating will not help — the server knows who you are and has decided you are not allowed.

Common Causes:

  • Insufficient permissions (e.g., non-admin trying to access admin routes)
  • IP address blocked by firewall or access list
  • Directory listing disabled and no index file
  • File permissions preventing the web server from reading files
  • .htaccess or Nginx deny rules
  • ModSecurity WAF blocking the request
# Check file permissions (Linux)
$ ls -la /var/www/mysite/
drwx------ 2 root root 4096 Mar 17 10:00 .
# Problem: www-data cannot read this directory!

# Fix permissions
$ sudo chmod 755 /var/www/mysite/
$ sudo chown -R www-data:www-data /var/www/mysite/

404 Not Found

The server cannot find the requested resource. This is the most recognized HTTP error — everyone has seen a 404 page. It means the URL does not correspond to any resource on the server.

Common Causes:

  • Typo in the URL
  • Page or file was deleted or moved without a redirect
  • Broken internal links
  • Missing Nginx rewrite rules (e.g., Laravel/WordPress pretty URLs not configured)
  • Case sensitivity (Linux filesystems are case-sensitive: /About is not /about)
# Nginx: Fix for pretty URLs (Laravel, WordPress, etc.)
location / {
try_files $uri $uri/ /index.php?$query_string;
}

405 Method Not Allowed

The HTTP method (GET, POST, PUT, DELETE, etc.) is not supported for the requested URL. For example, trying to POST to an endpoint that only accepts GET requests.

How to Fix: Check the API documentation for allowed methods. The response should include an Allow header listing the supported methods.

429 Too Many Requests

The client has sent too many requests in a given time period (rate limiting). The server is protecting itself from abuse or overload.

Common Causes:

  • API rate limit exceeded
  • Too many login attempts
  • Aggressive web scraping or crawling
  • Misconfigured automated scripts

How to Fix: Check the Retry-After header for when you can retry. Implement exponential backoff in your client code. If you are the server admin, adjust rate limits or whitelist the client IP.

5xx Server Error Codes

Server errors are the most critical because they indicate a problem on the server side. The client's request was valid, but the server failed to process it.

500 Internal Server Error

The most generic server error. Something went wrong on the server, but the server cannot be more specific about what. This is the catch-all for unhandled exceptions, fatal errors, and unexpected conditions.

Common Causes:

PHP Applications

  • Syntax errors in PHP files
  • Missing PHP extensions
  • Database connection failure
  • Permission denied on config files
  • Memory limit exceeded
  • Invalid .htaccess directives

Node.js / Python Apps

  • Unhandled promise rejections
  • Module import errors
  • Environment variable missing
  • Database migration not run
  • Disk full (cannot write logs)
  • Application crash loop
# Check PHP error logs
$ tail -20 /var/log/php8.3-fpm.log

# Check Nginx error log
$ tail -20 /var/log/nginx/error.log

# Check application logs
$ tail -20 /var/www/myapp/storage/logs/laravel.log

502 Bad Gateway

Nginx (acting as a reverse proxy or gateway) received an invalid response from the upstream server. This means the backend application either crashed, is not running, or returned a response that Nginx cannot understand.

Common Causes:

  • PHP-FPM is not running or has crashed
  • Backend application (Node.js, Python, etc.) is down
  • PHP-FPM socket file does not exist or has wrong permissions
  • Backend is returning malformed responses
  • Upstream timeout on initial connection
# Check if PHP-FPM is running
$ sudo systemctl status php8.3-fpm
● php8.3-fpm.service - The PHP 8.3 FastCGI Process Manager
Active: inactive (dead)

# Restart PHP-FPM
$ sudo systemctl restart php8.3-fpm

# Check if the socket exists
$ ls -la /var/run/php/php8.3-fpm.sock
srw-rw---- 1 www-data www-data 0 Mar 17 10:00 /var/run/php/php8.3-fpm.sock
502 is Almost Always a Backend Problem
When you see a 502, Nginx is working fine — it is the upstream server (PHP-FPM, Node.js, Python, etc.) that is the problem. Do not restart Nginx. Instead, check and restart the backend service. The Nginx error log will tell you exactly which upstream failed and why.

503 Service Unavailable

The server is temporarily unable to handle the request. This is commonly used during planned maintenance or when the server is overloaded. Unlike 502 (upstream is broken), 503 means the server itself is aware of the issue and is intentionally refusing requests.

Common Causes:

  • Server is in maintenance mode
  • Too many active connections (all workers busy)
  • Rate limiting triggered at the server level
  • Application deploying (brief window during restart)
  • Resource exhaustion (CPU, memory, disk)
# Check server load
$ uptime
10:30:01 up 45 days, load average: 28.50, 25.10, 20.00

# Check memory usage
$ free -h
total used free shared buff/cache available
Mem: 31Gi 29Gi 512Mi 256Mi 1.2Gi 1.5Gi

# Check PHP-FPM active processes
$ sudo systemctl status php8.3-fpm | grep Processes

504 Gateway Timeout

Nginx did not receive a timely response from the upstream server. The backend is running but took too long to respond. This is different from 502 (backend is down) — in a 504, the backend is alive but slow.

Common Causes:

  • Long-running database queries
  • External API calls that are slow or hanging
  • Large file processing (image manipulation, report generation)
  • Deadlocks in the application
  • PHP max_execution_time exceeded
  • Nginx proxy_read_timeout too short
# Increase Nginx proxy timeout
location / {
proxy_pass http://127.0.0.1:3000;
proxy_read_timeout 300s;
proxy_connect_timeout 10s;
proxy_send_timeout 300s;
}

# For PHP-FPM, also increase PHP limits:
; php.ini
max_execution_time = 300

; PHP-FPM pool conf
request_terminate_timeout = 300s

Quick Reference: Troubleshooting by Status Code

CodeFirst CheckSecond CheckThird Check
400Request body formatRequired parametersContent-Type header
401Auth token/API keyToken expirationCorrect auth header format
403File permissionsFirewall/IP blockUser role/permissions
404URL spellingNginx rewrite rulesFile exists on disk
405HTTP method usedAPI documentationCORS preflight
429Retry-After headerSending rateRate limit config
500Application error logPHP/Node error logFile permissions
502Backend service running?Socket file exists?Nginx error log
503Server load (uptime)Memory usage (free)Maintenance mode?
504Backend response timeDatabase slow queriesProxy timeout config

Reading Status Codes in Practice

You can check HTTP status codes using various tools:

# curl: Show only status code
$ curl -o /dev/null -s -w "%{http_code}\n" https://example.com
200

# curl: Show response headers (includes status code)
$ curl -I https://example.com
HTTP/2 200
content-type: text/html
server: nginx

# curl: Follow redirects and show all status codes
$ curl -ILs https://example.com | grep HTTP
HTTP/2 301
HTTP/2 200

# wget: Show server response
$ wget --spider -S https://example.com 2>&1 | grep "HTTP/"
HTTP/1.1 200 OK

Status Codes and APIs

RESTful APIs rely heavily on status codes to communicate the result of operations. Here is how well-designed APIs use status codes:

OperationSuccess CodeCommon Error Codes
GET /users200 OK401, 403, 500
GET /users/42200 OK401, 403, 404, 500
POST /users201 Created400, 401, 409 (conflict), 422, 500
PUT /users/42200 OK400, 401, 403, 404, 422, 500
PATCH /users/42200 OK400, 401, 403, 404, 422, 500
DELETE /users/42204 No Content401, 403, 404, 500
422 Unprocessable Entity vs 400 Bad Request
Both indicate the request cannot be processed, but for different reasons. 400 means the request is syntactically invalid (bad JSON, wrong content type). 422 means the request is syntactically correct but semantically invalid (email already exists, password too short, invalid enum value). Many modern APIs use 422 for validation errors because it is more specific.

Status Codes and SEO

Search engines use status codes to understand your site structure and make indexing decisions.

Good for SEO

  • 200 — Content is valid, index it
  • 301 — Pass link equity to new URL
  • 304 — Content unchanged, use cache

Bad for SEO

  • 404 — Page removed from index after repeated occurrence
  • 500/502/503 — Temporary: search engines retry. Persistent: page deindexed
  • Soft 404 — Returns 200 but shows "page not found" content. Confuses crawlers
Avoid Redirect Chains
A redirect chain occurs when URL A redirects to URL B, which redirects to URL C. Each hop slows page load and dilutes link equity. Search engines follow up to 10 redirects but prefer direct paths. Audit your redirects and ensure each one goes directly to the final destination (301 A directly to C).

Less Common but Important Codes

CodeNameWhen You Will See It
100ContinueClient sent headers, server says "go ahead with the body"
101Switching ProtocolsWebSocket upgrade response
206Partial ContentRange requests (video streaming, file resume)
307Temporary RedirectLike 302, but preserves HTTP method (POST stays POST)
308Permanent RedirectLike 301, but preserves HTTP method
409ConflictResource state conflict (e.g., duplicate entry)
410GoneResource permanently deleted (stronger than 404 for SEO)
413Payload Too LargeUpload exceeds client_max_body_size
418I'm a TeapotEaster egg from RFC 2324 (yes, it is real)
422Unprocessable EntityValidation errors in the request data
520-527Cloudflare CustomCloudflare-specific errors (not standard HTTP)
Key Takeaway
HTTP status codes are your first diagnostic tool when something goes wrong. Learn the big ones — 200, 301, 400, 401, 403, 404, 500, 502, 503, 504 — and you will be able to diagnose the vast majority of web issues. Always check the server error logs for 5xx errors, check your request for 4xx errors, and remember that 502 means "the backend is down" while 504 means "the backend is too slow." Bookmark this guide and refer to the troubleshooting table whenever you encounter an unfamiliar status code.
Share: