A 500 Internal Server Error means the server accepted the request but failed to complete it: the web server configuration is broken, a PHP script died with a fatal error, or it ran out of memory. The error page never names the cause, but one line in the domain’s error log almost always does. We deliberately reproduced eight common causes of a 500 on a test site and recorded, for each one, what the visitor sees, which line appears in the log and what to do next.
How we tested
On 10 November 2026, on a test bench: an Ubuntu 24.04.5 container, nginx 1.24.0 in front of Apache 2.4.58 with mod_proxy_fcgi (a typical control panel setup), PHP-FPM 8.3.6 with memory_limit 128M and OPcache on, MariaDB 10.11.14, WordPress 6.4.3. We also tested nginx talking to PHP-FPM directly, without Apache. Each fault was reproduced one at a time; we recorded the status code and response size with curl and the exact log line, then reverted the change. File paths in the examples belong to the bench and will differ on your hosting. This is how a test site behaved, not data from RichHost servers.
What the visitor sees and what it tells you
Before you even open the log, the look of the error page hints at which layer failed. On the bench every type of fault produced its own recognizable response:
| What the browser shows | Response on the bench | Where to look |
|---|---|---|
| Grey Apache page “Internal Server Error … misconfiguration” | 500, 531 bytes | Configuration: .htaccess, mod_rewrite rules |
| Blank white page | 500, 0 bytes | PHP crashed before WordPress started, or in a standalone script |
| “There has been a critical error on this website” | 500, 2726 bytes | PHP error inside WordPress: plugin, theme, memory |
| “Requirements Not Met” mentioning the MySQL extension | 500, 2888 bytes | PHP extension mysqli is not loaded |
| “Error establishing a database connection” | 500, 2527 bytes | Database: credentials in wp-config.php or the MySQL server |
| Parse error or Fatal error text right on the page | 200 | display_errors is on: the cause is visible, but to everyone |
WordPress shows “Error establishing a database connection” when it cannot reach the database, and no PHP line is logged in that case: see our guide to the database connection error for what to check. If the server returns 502 or 503 instead of 500, the problem is not in the site code but in the link between the web server and PHP. On the same bench, a stopped PHP-FPM produced exactly a 503 with an AH01079 line in the Apache log; the steps for that case are in our article on the 503 Service Unavailable error.
How to find the right log line in one minute
A 500 is recorded in the web server’s error log even when no separate PHP log is configured. When PHP-FPM has no log file of its own, it passes the error text to the web server, which writes it to the domain log. On the bench this appeared as a line with the code AH01071 in the Apache log and the phrase “FastCGI sent in stderr” in the nginx log.
- Load the failing page once more and note the time. Logs can be long, and the timestamp narrows the search to a few lines.
- In your hosting control panel, open the logs of the domain and choose the error log. On many panel servers these logs live in
/var/log/apache2/domains/and/var/log/nginx/domains/, but on shared hosting the panel is the easiest way to read them. - If you downloaded the log or can connect via SSH, filter only the lines that explain a 500:
grep -E "AH00124|AH01071|Invalid command|PHP (Fatal|Parse) error" error.log | tail -n 5
- Read the line from the end. It contains the file path and line number, for example
wp-content/plugins/bench-fatal/bench-fatal.php:3. The folder afterplugins/orthemes/is the culprit.
One detail that causes confusion: WordPress writes timestamps to its own log in UTC, so adjust for your time zone when matching entries.
Table: log line, cause, what to do
Lines are shortened, but the key words are kept verbatim so you can search for them in your own log.
| Log line | Cause | What to do |
|---|---|---|
Invalid command 'RewriteEngin', perhaps misspelled |
Typo in a .htaccess directive | Rename .htaccess, check the site, fix the line |
Invalid command 'php_value' |
PHP runs via PHP-FPM, Apache does not know php_value | Remove the line, move the setting to .user.ini |
AH00124: Request exceeded the limit of 10 internal redirects |
A RewriteRule rewrites the URL to itself | Add a RewriteCond or restore the standard WordPress block |
PHP Parse error: syntax error ... on line 12 |
Syntax error after a manual edit | Fix the reported line or the line above it |
Call to undefined function ...() in .../plugins/name/ |
Plugin or theme incompatible with the PHP version or another plugin | Rename the plugin folder in the file manager |
Allowed memory size of 134217728 bytes exhausted |
The script hit memory_limit (128 MB here) | Find the plugin from the path, raise the limit if needed |
Call to undefined function mysqli_connect() |
PHP extension not loaded | Enable the extension for the PHP version the site uses |
Failed opening required ... Permission denied |
The PHP user cannot read the file | Restore the site owner, 644 for files and 755 for folders |
| No line, page says Error establishing a database connection | Wrong database credentials or MySQL is down | Check DB_NAME, DB_USER, DB_PASSWORD, DB_HOST |
| No line, page says Requirements Not Met | WordPress itself detected that mysqli is missing | Same as the mysqli_connect row |
What we saw on the bench
.htaccess and php_value: a 500 before PHP even starts
Both faults returned the same grey Apache page in about one millisecond, because the request never reached PHP. The typo RewriteEngin On and the line php_value memory_limit 256M produced almost identical entries tagged core:alert. The second case is typical after a migration: the old host ran PHP as an Apache module, the new one runs PHP-FPM, and php_value suddenly becomes an unknown command. Move such settings to a .user.ini file in the site root:
upload_max_filesize = 64M
On the bench the new .user.ini did not apply immediately: PHP rereads these files at most once every 300 seconds (the user_ini.cache_ttl setting), and the value changed only after PHP was restarted. So wait five minutes before deciding the setting does not work. Values the host has locked at server level cannot be changed through .user.ini. For upload limits specifically, see how to increase upload_max_filesize.
Syntax error: a blank page, or status 200 with the error text
A missing semicolon in wp-config.php with display_errors off produced a zero-byte 500: a white page with no text at all. WordPress cannot help here, because the error happens before it loads. The full message was in the log:
AH01071: Got error 'PHP message: PHP Parse error: syntax error, unexpected identifier "define" in /srv/cw3/www/wp-config.php on line 12'
The semicolon was missing on line 11, yet PHP reported line 12: the parser notices the error only at the next statement, so always check the line above as well. Then we turned display_errors on, and the result was not obvious: the server answered with status 200 and the page showed the Parse error text with the full file path on the server. A monitor that checks only the status code will consider the site healthy, while every visitor sees your folder structure. Do not display errors on a live site: they are in the log anyway.
Plugin fatal error and memory exhaustion
A call to a nonexistent function in a plugin and an endless memory allocation looked the same to WordPress: status 500 and the page “There has been a critical error on this website”. Only the log tells them apart:
PHP Fatal error: Uncaught Error: Call to undefined function rh_function_that_does_not_exist() in .../wp-content/plugins/bench-fatal/bench-fatal.php:3 PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 2097152 bytes) in .../wp-content/plugins/bench-memory/bench-memory.php on line 3
134217728 bytes is exactly 128 MB, the current memory_limit. Renaming the plugin folder brought the site back to 200 on the next request. Both cases are covered in detail in our guides to the WordPress critical error and to raising memory_limit. Raising the limit makes sense when a plugin genuinely needs more memory, not when it is stuck in an endless loop as in our test.
Missing PHP extension
We started PHP-FPM without the mysqli extension. WordPress checked for it on its own and showed the “Requirements Not Met” page with status 500, and not a single line appeared in the logs. A standalone script calling mysqli_connect() returned a blank page and the line Call to undefined function mysqli_connect(). Note that php -m in the terminal still listed mysqli at that moment, because the command line PHP and PHP-FPM read different configuration. Check extensions in the control panel for the right PHP version or with phpinfo() in the browser, not in the console.
File permissions and the OPcache trap
We gave a WordPress file to root with mode 600, so PHP-FPM could not read it. Yet the site kept loading with status 200: OPcache still held the compiled copy in memory. After a PHP restart the same site returned 500 with Failed to open stream: Permission denied in wp-settings.php. In practice a wrong chown or chmod can surface hours later, after a routine PHP restart, when the link to the change is no longer obvious. If the script the visitor requests is itself unreadable, the response is not 500 but 403 with the text Access denied. Normal values are 644 for files and 755 for folders, owned by the site user.
Internal rewrite loop
The rule RewriteRule ^(.*)$ /index.php/$1 [L] without a condition rewrites the URL to itself. Apache stops after ten internal redirects and returns 500:
AH00124: Request exceeded the limit of 10 internal redirects due to probable configuration error.
This is not the same as an ERR_TOO_MANY_REDIRECTS loop: there the browser bounces between URLs, here the loop happens inside the server and the browser only sees a 500. A condition before the rule fixes it, as does restoring the standard WordPress block:
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteRule ^(.*)$ /index.php/$1 [L]
How to enable the WordPress error log safely
If the web server log is not available or is full of unrelated entries, turn on the WordPress log. Add this to wp-config.php above the line require_once ABSPATH . 'wp-settings.php';:
define( 'WP_DEBUG', true ); define( 'WP_DEBUG_LOG', '/home/user/logs/wp-errors.log' ); define( 'WP_DEBUG_DISPLAY', false ); @ini_set( 'display_errors', 0 );
Replace /home/user/logs/ with a folder in your account outside the site’s public directory. This matters: with a plain true the log goes to wp-content/debug.log, and on the bench that file opened in any browser with status 200, server paths included. With a separate path, visitors still saw only the critical error page while the log received the line with the cause. Once you have found it, set WP_DEBUG back to false: the WordPress documentation advises against debug mode on live sites.
When to contact hosting support
Contact support if the log has no line for the time of the error, if the 500 comes and goes without any changes on your side, or if several sites on the account fail at once. Include the exact time, the page URL, the log line and what you have already checked: with these details the answer will be specific. To tell a site problem from a server problem quickly, see our guide to diagnosing hosting problems in 15 minutes. RichHost support works from 10:00 to 20:00 Kyiv time and usually replies within 30 minutes. On RichHost shared hosting plans sites are managed in our own control panel with an AI assistant.
FAQ
Can the hosting provider cause a 500, not the site?
It can, but if the log has a PHP line pointing to your files, the cause is in the site code or settings. Server-side failures more often show up as 502 or 503, or leave the log empty.
Why does the site load while wp-admin returns 500?
The error happens only in code that runs in the admin area: a plugin active only there, or an operation that runs out of memory. The log line points to the exact file; then proceed as for the public site.
Can I leave display_errors on to see errors faster?
No. On the bench the error page returned status 200 and showed visitors the full file paths. Send errors to the log, not to the screen.
The error went away by itself. Can I ignore it?
Better find the log entry for that time. Our permissions test showed that a fault can hide behind OPcache and come back after a PHP restart.



