500 Internal Server Error: how to find the cause and fix it

A 500 hides its reason on purpose. Where to look first, the usual causes from unhandled exceptions to full disks, and the extra checks for WordPress and PHP sites.

· 5 min read · By the Spot Downtime team

500 Internal Server Error is the server admitting something went wrong and it doesn't want to say what. That's deliberate: the details belong in your logs, not on a page anyone can read. So the first rule of fixing a 500 is simple. Stop looking at the browser and open the logs.

The first five minutes

  1. Did something just change? A deploy, a config change, a package update or a migration. If yes, rolling back is usually faster than debugging.
  2. Is it every page, or one? Every page points to configuration, the database or the platform. One page points to a bug in that page's code.
  3. Read the error log. You're looking for a stack trace with a timestamp matching the failed request.
bash
journalctl -u your-app --since "10 min ago"    # systemd services
docker logs --since 10m your-container          # containers
sudo tail -n 100 /var/log/nginx/error.log       # proxy side
tail -n 100 /var/log/php*-fpm.log               # PHP

The usual causes

An unhandled exception

A null value where code expected an object, a missing field in an API response, a division by zero. The stack trace names the file and line. Fix it, and add a test for the input that caused it.

A broken configuration

A missing environment variable after a deploy, a syntax error in .htaccess (Apache returns 500 for the whole folder), or wrong file permissions on a script. These hit every page at once.

The database or another dependency

The database is down, out of connections, or a migration hasn't run, so a query references a column that doesn't exist. Errors mention connection refused, too many connections or an unknown column.

Resource limits

The disk is full, so nothing can write; or PHP's memory_limit is hit; or the process can't open more files.

bash
df -h          # disk space
free -m        # memory

WordPress and PHP sites

  • Turn on logging (not on-screen display) with WP_DEBUG and WP_DEBUG_LOG in wp-config.php, then read wp-content/debug.log.
  • Rename the plugins folder to disable all plugins at once. If the site comes back, re-enable them one by one.
  • Rename .htaccess to rule out a broken rewrite rule.

Don't show stack traces to visitors

Debug pages leak file paths, queries and sometimes secrets. Show a friendly error page with the right 500 status, and send the details to your logs or an error tracker.

Catch the intermittent ones

A 500 that happens once an hour is the hardest to fix, because it's never happening when you look. A monitor that records every failed check with its time and status code turns “it's flaky” into a pattern you can match against your logs. Spot Downtime checks as often as every 30 seconds and keeps that history per monitor.

Website down checkerCheck from outside whether a URL is returning a 500 right now, with the exact status code and response time.

Seeing a 502, 503 or 504 instead? Those point somewhere else: read 502 vs 503 vs 504.

Keep reading