Short answer: Website error codes tell you who failed. A 4xx code (403, 404) means the server understood the request but refused it or could not find the page: think permissions, a missing index file, a deleted or renamed URL. A 5xx code (500, 502, 503, 504) means the server or the application behind it failed: a PHP error, PHP-FPM not running, a backend that is too slow, or a limit being hit. The status code narrows the cause; the web server’s error log names it. Below is what each code means, what the log says when it happens, and the first fix to try.
Applies to nginx 1.29.8, Apache 2.4.69 and PHP-FPM 8.3.35 (lab reproduction of 403, 404, 500, 502, 503, 504)
We reproduced every error on 9 October 2026 in a lab with nginx 1.29.8, Apache 2.4.69 and PHP-FPM 8.3.35, and copied the real status codes and log lines into this guide. Two results surprised us: Apache returns 503 where nginx returns 502 for the same stopped PHP backend, and a server that does not answer at all gives a 504, not a 502.
Table of Contents
Website error codes at a glance



| Code | What it means | Most common cause | Check first |
|---|---|---|---|
| 403 Forbidden | The server refuses to serve the path | Wrong file permissions, no index file, a firewall or WAF rule | Error log, file permissions |
| 404 Not Found | Nothing exists at that URL | Page deleted or renamed without a redirect, wrong document root, broken permalinks | Access log, the exact URL |
| 500 Internal Server Error | The application or configuration failed | PHP fatal error, memory limit, a typo in .htaccess | PHP error log, web server error log |
| 502 Bad Gateway | The proxy got no valid answer from the backend | PHP-FPM stopped or wrong socket or port | Is PHP-FPM running? nginx error log |
| 503 Service Unavailable | The server cannot handle the request right now | Backend down (Apache), rate limit, maintenance mode, resource limits | Error log, PHP-FPM and LiteSpeed limits |
| 504 Gateway Timeout | The backend did not answer in time | Slow PHP or database query, backend server unreachable | Slow queries, timeout settings |
Where to find the error log
The status code tells you which family of problem it is; the log line tells you the actual cause. The usual locations:
- cPanel (Apache, EasyApache 4):
/etc/apache2/logs/error_log; PHP errors also go toerror_logfiles in the site’s folders, or the PHP-FPM log of the account. - DirectAdmin:
/var/log/httpd/domains/example.com.error.log(and.logfor the access log). - nginx:
/var/log/nginx/error.log, or theerror_logset in the site’s server block. - LiteSpeed:
/usr/local/lsws/logs/error.logandstderr.log. - WordPress: set
WP_DEBUGandWP_DEBUG_LOGto true andWP_DEBUG_DISPLAYto false inwp-config.php; errors are written towp-content/debug.log, not shown to visitors.
Watch the log while you load the failing page: tail -f /var/log/nginx/error.log.
403 Forbidden
A 403 means the server found the path but will not serve it. We triggered the two most common causes, a folder without an index file and a file the web server user cannot read:
$ curl -s -o /dev/null -w "%{http_code}\n" http://errlab.test/files/
403
$ curl -s -o /dev/null -w "%{http_code}\n" http://errlab.test/secret.html
403
nginx logged:
[error] directory index of "/usr/share/nginx/html/files/" is forbidden
[error] open() "/usr/share/nginx/html/secret.html" failed (13: Permission denied)
Apache logged:
[autoindex:error] AH01276: Cannot serve directory /usr/local/apache2/htdocs/files/: No matching DirectoryIndex (index.html) found, and server-generated directory index forbidden by Options directive
[core:error] (13)Permission denied: AH00132: file permissions deny server access: /usr/local/apache2/htdocs/secret.html
Fix: add an index.html or index.php to the folder, and give files 644 and folders 755, owned by the site’s user (the chmod calculator explains the numbers). If the log shows nothing, the 403 comes from somewhere else: a ModSecurity or Imunify360 rule, a Deny or Require line in .htaccess, a firewall block on your IP, or Cloudflare. Never “fix” a 403 with chmod 777.
404 Not Found
A 404 means there is no file or route at that URL. In our test, neither nginx (using try_files) nor Apache at its default log level wrote anything to the error log for a 404; it only appears in the access log:
172.21.0.1 - - [09/Oct/2026:18:46:47 +0000] "GET /missing-page HTTP/1.1" 404 236
So search the access log, not the error log: grep ' 404 ' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head lists the most requested missing URLs.
Fix: if the page moved, add a 301 redirect to the new address (the .htaccess redirect generator writes the rule, and the redirect checker confirms it). On Linux, URLs are case-sensitive, so /Guide.html and /guide.html are different files. If every WordPress page except the home page returns 404, the rewrite rules are missing: save Settings → Permalinks once, which rewrites .htaccess.
500 Internal Server Error
A 500 is a generic failure inside the server or the application. We produced three of the most common causes: a PHP fatal error, PHP running out of memory, and a typo in .htaccess. All three returned 500:
NOTICE: PHP message: PHP Fatal error: Uncaught Error: Call to undefined function undefined_function_srvs() in /var/www/php/fatal.php:1
NOTICE: PHP message: PHP Fatal error: Allowed memory size of 16777216 bytes exhausted (tried to allocate 67108896 bytes) in /var/www/php/memory.php on line 1
[core:alert] /usr/local/apache2/htdocs/badht/.htaccess: Invalid command 'RewriteEngin', perhaps misspelled or defined by a module not included in the server configuration
One detail to know: on our first run PHP still had display_errors on, and the same broken scripts returned 200 with half a page and the error text printed in it. A page that loads “white” or cut off with status 200 can be exactly the same bug, just reported differently.
Fix: read the PHP error log first; it names the file and line. For memory errors, raise memory_limit for that site only, and find what uses so much memory. For WordPress, the file path usually points to the plugin or theme at fault: rename that plugin’s folder to disable it. For an .htaccess error, the log quotes the bad line; fix or remove it.
502 Bad Gateway
A 502 comes from a proxy, usually nginx, when the backend behind it (PHP-FPM, Node.js, another server) refuses the connection or returns something invalid. We pointed nginx at a PHP-FPM port where nothing listened:
$ curl -sI http://errlab.test/down.php | head -1
HTTP/1.1 502 Bad Gateway
[error] connect() failed (111: Connection refused) while connecting to upstream, upstream: "fastcgi://172.21.0.2:9001"
Fix: check that PHP-FPM runs (systemctl status php-fpm, or the version-specific service such as php8.3-fpm) and that nginx points to the same socket or port the pool listens on. With a Unix socket, the log says (2: No such file or directory) when the socket does not exist and (13: Permission denied) when nginx may not use it. Our nginx 502 connection refused guide goes through each case.
503 Service Unavailable
A 503 means the server is temporarily unable to handle the request. In our lab, three different things produced it:
- Apache with a stopped PHP backend. The same fault that gives a 502 on nginx gives a 503 on Apache:
AH00957: FCGI: attempt to connect to 172.21.0.2:9001 (php:9001) failedfollowed byAH01079: failed to make connection to backend. - Rate limiting. nginx’s
limit_reqanswers 503 by default. Four quick requests to a path limited to one per second returned200 200 503 503, logged aslimiting requests, excess: 1.982 by zone "one". Setlimit_req_status 429;so limits are not mistaken for an outage. - Maintenance. A planned
return 503, or WordPress’s.maintenancefile during updates; delete a leftover.maintenancefile in the site root if an update was interrupted.
On shared hosting, 503s also come from limits: LiteSpeed’s PHP process limits and CloudLinux LVE limits (which can also show as 508). See LiteSpeed 503 with lsphp on cPanel, DirectAdmin 503 and PHP-FPM and 508 Resource Limit Reached.
504 Gateway Timeout
A 504 means the proxy waited for the backend and gave up. We ran a PHP script that sleeps 10 seconds behind a 3-second timeout:
nginx: [error] upstream timed out (110: Operation timed out) while reading response header from upstream
Apache: [proxy_fcgi:error] (70007)The timeout specified has expired: AH01075: Error dispatching request to :8092: (polling)
We also stopped the backend container completely, so its address no longer answered at all. nginx did not return 502 but 504, with upstream timed out (110: Operation timed out) while connecting to upstream. A 504 on a backend that “should be fast” can therefore mean the backend server is down or a firewall drops the traffic.
Fix: find what is slow before raising timeouts: a heavy database query (the slow query advisor helps read the MySQL slow log), an external API call, or an import or backup job run from a web request. Move long jobs to cron or the command line. Raise fastcgi_read_timeout (nginx), ProxyTimeout (Apache) or PHP’s max_execution_time only for the specific path that needs it.
Cloudflare 52x errors
If the site is behind Cloudflare, these codes come from Cloudflare and describe its connection to your server:
| Code | Meaning | Check |
|---|---|---|
| 520 | The server sent an empty, unknown or invalid answer | Server error log at the same time; crashed PHP |
| 521 | The server refused the connection | Web server stopped, or the firewall blocks Cloudflare’s IP ranges |
| 522 | Connection to the server timed out | Server overloaded, firewall dropping packets, wrong origin IP |
| 523 | Origin unreachable | Wrong A record or routing problem |
| 524 | Connected, but no answer within 100 seconds | A slow script, same as a 504 |
| 525 | SSL handshake with the server failed | No valid TLS on the server with Full or Full (strict) mode |
| 526 | Invalid SSL certificate on the server | Expired or self-signed certificate with Full (strict) |
Check from outside first
An error you see may not be what everyone sees: a firewall can block only your IP, and a CDN can serve an old copy. Test from outside with our website down checker, look up any code in the HTTP status codes reference, or ask the Genie button at the bottom of this page with the exact error text.
Official documentation: RFC 9110: HTTP status codes, nginx limit_req module, Cloudflare 5xx errors.
Related guides: nginx 502: connect() failed (111) · LiteSpeed 503 on cPanel · 508 Resource Limit Reached.
Frequently asked questions
What is the difference between 4xx and 5xx website errors?
4xx codes mean the request could not be served as asked: the page does not exist (404) or access is refused (403). 5xx codes mean the server or the application failed while handling a valid request, for example a PHP error (500) or a backend that is down or too slow (502, 503, 504).
Why does my site show 502 Bad Gateway?
A proxy such as nginx could not get a valid answer from the backend, most often because PHP-FPM is stopped or nginx points to the wrong socket or port. The nginx error log shows connect() failed with the reason.
What is the difference between 502 and 504?
502 means the backend refused the connection or sent an invalid answer. 504 means it did not answer in time: a slow script, or a backend server that does not respond at all.
Why do I get 503 Service Unavailable?
Common causes are a stopped PHP backend on Apache, a rate limit, maintenance mode, or hosting resource limits on LiteSpeed or CloudLinux. The error log tells which one.
Why are 404 errors not in my error log?
Many servers record 404s only in the access log. Search the access log for ” 404 ” to find the missing URLs, then redirect moved pages with a 301.
Reading a lot of our guides? Go ad-free with srvScripts Pro for $6 a month. It also pays for new guides. Cancel any time.