✦ Blog

500 Internal Server Error: What It Means and How to Fix It

A 500 Internal Server Error means the server failed while handling a request. Common causes, the log commands that find the real one, and fixes by stack.

Upmonora team7 min read

Overview - 500 Internal Server Error: What It Means and How to Fix It

A 500 Internal Server Error means the server hit an unexpected problem while handling the request and could not return the page. It is a catch-all code: the server knows something failed, but the status does not say what. The real cause is almost always written in the server or application error log, so the fix starts there, not in the browser.

If you are a visitor, there is nothing to fix on your side: reload once, then try again later. If it is your site, this guide covers the usual causes, the log commands that tell you which one you have, and the fix for each common stack.

What a 500 error means

The HTTP specification defines 500 as the response for a server that "encountered an unexpected condition that prevented it from fulfilling the request". Two useful things follow from that:

  • The request arrived. DNS, the network and TLS all worked. This is not a connectivity problem.
  • The web server or the application broke while building the response. That is where to look.

The wording varies: 500 Internal Server Error (Apache, Nginx), HTTP ERROR 500 (Chrome's own page when the response has no body), "There has been a critical error on this website" (WordPress), or just a blank white page.

The most common causes

  1. An unhandled application error. An uncaught exception, a PHP fatal error, a call to a function that does not exist, or a syntax error in a file that was just edited. This is the most common cause by far.
  2. A bad .htaccess or server config. Apache answers 500 for a whole directory if its .htaccess contains a directive it does not understand or is not allowed to use. Rewrite rules that loop do the same on Apache and Nginx.
  3. Permissions and ownership. The application cannot write to its cache, session, upload or log directory. On hosts that run scripts as your own user (suEXEC, suPHP), a file or folder that is writable by everyone (777) is refused outright.
  4. Memory or time limits. PHP ends the request with a fatal error when it passes memory_limit or max_execution_time.
  5. A failed deploy. Missing dependencies (vendor/ or node_modules/), a missing environment variable, migrations that were not run, or code that needs a newer runtime than the server has.
  6. A database connection failure. Wrong credentials, a stopped database, or its connection limit reached. Most frameworks turn that into a 500.
  7. A full disk. Sessions, cache files and uploads can no longer be written, so pages that have nothing to do with each other start failing together.

How to find the real cause in the logs

Step 1: reproduce it and note the scope

curl -sS -o /dev/null -w "HTTP %{http_code} in %{time_total}s\n" https://example.com/broken-page

Try a few URLs. If one page fails, the problem is in that page's code path. If every page fails, think config, deploy, database or disk.

Step 2: read the web server error log

# Apache: Debian/Ubuntu, then RHEL/AlmaLinux
sudo tail -n 50 /var/log/apache2/error.log
sudo tail -n 50 /var/log/httpd/error_log

# Nginx (PHP-FPM errors usually show up here too)
sudo tail -n 50 /var/log/nginx/error.log

Swap tail -n 50 for tail -f and reload the page to watch the error appear as it happens.

Step 3: see which requests fail

# URLs that returned 500, most frequent first (default "combined" log format)
sudo awk '$9 == 500 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head

Step 4: read the application log

  • PHP-FPM: /var/log/php8.3-fpm.log on Debian/Ubuntu (the version number in the name follows your PHP version).
  • Laravel: storage/logs/laravel.log.
  • WordPress: wp-content/debug.log, once WP_DEBUG_LOG is switched on.
  • Node.js: sudo journalctl -u myapp -n 100 --no-pager under systemd, or pm2 logs myapp --lines 100 under PM2.
  • Shared hosting: the "Errors" page in cPanel, or an error_log file in the site folder.

Step 5: match the message

What the log saysCause
PHP Fatal error: Uncaught ... or Call to undefined functionApplication bug, or a missing PHP extension
Allowed memory size of ... bytes exhaustedMemory limit reached
Maximum execution time of 30 seconds exceededTime limit reached
.htaccess: Invalid command 'RewriteEngine'Apache module not enabled, or a mistyped directive
Request exceeded the limit of 10 internal redirectsRewrite loop (Apache)
rewrite or internal redirection cycleRewrite or try_files loop (Nginx)
Permission deniedOwnership or permissions
SQLSTATE[HY000] [2002] or [1045] Access deniedDatabase unreachable, or wrong credentials
No space left on deviceFull disk (confirm with df -h)

Do not switch on display_errors on a live site to see the message in the browser. It shows file paths, queries and sometimes credentials to every visitor. Log errors, do not display them.

Fixes by stack

Apache

Run sudo apachectl configtest to check the main configuration. That command does not read .htaccess files, so test those by renaming:

mv .htaccess .htaccess.off

If the homepage or a static file loads again, the file is the problem. The usual culprits are mod_rewrite not being enabled (on Debian/Ubuntu: sudo a2enmod rewrite && sudo systemctl restart apache2), php_value lines on a server that runs PHP through PHP-FPM instead of mod_php (move those settings to a .user.ini file), and a rewrite rule that matches its own target.

Nginx + PHP-FPM

Nginx passes PHP's 500 straight through. The detail is in the Nginx error log, in a line starting FastCGI sent in stderr: "PHP message: PHP Fatal error. Fix the code it names, or install the extension it is missing, for example mbstring on Ubuntu:

sudo apt install php8.3-mbstring
sudo systemctl restart php8.3-fpm

For a redirection cycle, check the root path and the last argument of try_files: it usually points at a file that does not exist. After any config change, run sudo nginx -t && sudo systemctl reload nginx. If PHP-FPM is not running at all, Nginx returns a 502 instead of a 500.

WordPress

Rename .htaccess, then open Settings → Permalinks and click Save to generate a clean one. If that does not help, rename wp-content/plugins to switch every plugin off, and turn on WP_DEBUG_LOG to get the exact file and line. Our WordPress recovery checklist walks through each step.

Node.js

Express returns 500 when an unhandled error reaches its default error handler, and prints the stack trace to stderr. Add your own handler after all the routes so every failure is logged in one place:

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: 'Internal Server Error' });
});

In Express 4, an error thrown inside an async route handler never reaches that handler unless you catch it and call next(err). Express 5 forwards it for you.

After a failed deploy

Roll back first, investigate second. Then check the usual gaps: dependencies installed (composer install, npm ci), environment variables present on the server, database migrations run, and a runtime version that matches what the code needs (php -v, node -v).

Permissions, on any stack

A typical PHP site wants directories at 755 and files at 644, owned by the user the application runs as, with only the cache, upload and log folders writable by the web server:

sudo find /var/www/example -type d -exec chmod 755 {} \;
sudo find /var/www/example -type f -exec chmod 644 {} \;

Never "fix" a permissions error with chmod -R 777. It is a security hole, and on suEXEC hosts it causes the 500 it was meant to cure.

500 vs 502, 503 and 504

CodeWhat failedLook at
500 Internal Server ErrorThe application or web server broke while handling the requestApplication and server error logs
502 Bad GatewayA proxy got no valid answer from the app server behind itWhether the app process is running
503 Service UnavailableThe server is overloaded or in maintenanceLoad, health checks, maintenance mode
504 Gateway TimeoutA proxy gave up waiting for the app serverSlow queries and slow external calls

The short version: a 500 means the application answered with a failure. A 502 or 504 means the proxy in front of it could not get a usable answer at all.

How monitoring catches 500s

500s are often partial. A cached homepage keeps loading while login, search or checkout fails on every request, and the first person to notice is a customer. An external website monitor requests the page on a schedule and records the status code of every check, so a 500 shows up within minutes, not hours.

In Upmonora, any status outside the codes you marked as healthy counts as a failed check. After the number of consecutive failures you choose (two by default), an incident opens and you are alerted by email, Slack, Microsoft Teams or webhook. Two habits make that much more useful:

  • Monitor pages that run code. Add the login page, a search URL or a health endpoint that touches the database, not just the homepage.
  • Read the pattern. AI insights group recurring failure types such as 5xx responses and explain them in plain language, which helps with the 500 that only appears now and then.

To see what a URL returns right now, run it through the free website checker. To be told the next time it breaks, the free plan covers 5 monitors checked every 5 minutes.

Frequently asked questions

What does 500 Internal Server Error mean?

The server ran into an unexpected problem while handling the request and could not return the page. It is a generic code: the real reason is recorded in the server or application error log, not shown in the browser.

Is a 500 error my fault or the website's?

The website's. A 500 is produced by the server after your request arrived, so your connection and browser are working. As a visitor you can reload once and try again later, but only the site owner can fix it.

How do I fix a 500 Internal Server Error on my site?

Read the web server and application error logs for the time of the failed request. The log line names the cause, most often an application exception, a bad .htaccess or config directive, a permissions problem, a memory or time limit, a failed deploy or a database connection failure.

Does a 500 error hurt SEO?

A short one does not. If Googlebot keeps getting 5xx responses for hours or days, it slows down crawling, and URLs that keep failing can eventually be dropped from the index until they recover.