How to Fix a 500 Internal Server Error (Step by Step)

A 500 Internal Server Error means something broke on the server, but the server can't tell you exactly what. Here's how to find the cause and fix it.

Written by Timothy Bramlett ยท

A 500 Internal Server Error is the most frustrating HTTP error because it tells you almost nothing. Something went wrong on the server, but the server won't say what. If you're a visitor, all you can do is wait. If you own the site, you need to dig into logs and configs to find the real problem.

This guide covers what a 500 error actually means, how to find the cause using error logs, and step by step fixes for WordPress, PHP, Node.js, and Python applications. Every fix includes actual commands you can run.

What Is a 500 Internal Server Error?

A 500 Internal Server Error is an HTTP status code that means the server encountered an unexpected condition that prevented it from fulfilling the request. It's a generic catch-all error. The server knows something went wrong, but it can't (or won't) tell you exactly what.

This is different from a 502 Bad Gateway (where one server can't reach another) or a 503 Service Unavailable (where the server is overloaded or in maintenance). A 500 means the server's own code hit an unhandled error. The bug is in the application itself, not in the network or server capacity.

Common triggers include:

  • Code errors: Syntax errors, null pointer exceptions, unhandled exceptions in PHP, Python, or Node.js
  • Broken .htaccess: Malformed rewrite rules or invalid directives on Apache servers
  • Exhausted PHP memory: Scripts exceeding the memory_limit or max_execution_time
  • File permission issues: The web server can't read or execute application files
  • Database connection failures: Application can't connect to MySQL, PostgreSQL, or another database
  • Missing dependencies: A required module, package, or file is missing from the server

You might see the error displayed differently depending on the server or application:

  • 500 Internal Server Error
  • HTTP Error 500
  • Internal Server Error
  • HTTP 500
  • 500 Error
  • The server encountered an internal error (common in Java/Tomcat applications)

They all mean the same thing. The real answer is always in the error logs.

Quick Fixes (Try These First)

Before diving into server configurations, try these quick checks.

1. Reload the Page

Some 500 errors are transient. A script might have timed out, or the database was briefly unavailable. Press Ctrl + F5 (Windows) or Cmd + Shift + R (Mac) to hard reload.

2. Check If It's Just One Page

Try loading a different page on the same site. If only one page throws a 500, the bug is in the code specific to that page (a bad template, a broken route handler, or a failed database query). If every page returns 500, the problem is more fundamental: a missing config file, a broken .htaccess, or a crashed backend process.

3. Undo Recent Changes

If the 500 started after a deploy, plugin update, or config change, roll it back. Most 500 errors in production are caused by a recent change. If you're using Git:

# Check what changed recently:
git log --oneline -10

# Revert to the previous commit (creates a new commit, safe for production):
git revert HEAD

4. Check If the Site Is Down for Everyone

Use our free ping test to check whether the site responds at all. If it returns 500 for everyone, the problem is confirmed on the server side.

Still seeing the error?

The answer is in the error logs. That's always your next step with a 500.

Check Error Logs (The Most Important Step)

A 500 error is deliberately vague to users (for security reasons). But the server records the actual error in its log files. This is the single most important step for any 500 error. Everything else is guessing.

Nginx Error Log

sudo tail -50 /var/log/nginx/error.log

Apache Error Log

sudo tail -50 /var/log/apache2/error.log

PHP Error Log

# Find where PHP logs errors:
php -i | grep error_log

# Common locations:
sudo tail -50 /var/log/php8.2-fpm.log
sudo tail -50 /var/log/php_errors.log

Node.js Application Log

# If using PM2:
pm2 logs --lines 50

# If using systemd:
sudo journalctl -u your-app-service -n 50

Python/Django/Flask Log

# If using Gunicorn with systemd:
sudo journalctl -u gunicorn -n 50

# Django debug log (if configured):
tail -50 /path/to/your/project/debug.log

The error log will contain the actual exception, stack trace, or error message. Once you know the real error, you can fix it directly. The sections below cover the most common causes by platform.

Fixing 500 Errors on WordPress

WordPress is the most common platform where people encounter 500 errors. The typical causes are a corrupt .htaccess file, a bad plugin, PHP memory limits, or database connection issues.

Step 1: Enable WordPress Debug Mode

WordPress hides error details by default. Turn on debug logging to see the actual error:

// In wp-config.php (before "That's all, stop editing!"):
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);  // Don't show errors to visitors

After enabling this, reproduce the error and check the log:

tail -50 wp-content/debug.log

This log will show you the exact PHP error, file, and line number causing the 500.

Step 2: Fix or Replace .htaccess

A corrupt .htaccess file is one of the most common causes of 500 errors on WordPress with Apache. Rename the current file and let WordPress generate a fresh one:

# Rename the current .htaccess:
mv /var/www/html/.htaccess /var/www/html/.htaccess_backup

# Create a fresh default WordPress .htaccess:
cat > /var/www/html/.htaccess << 'HTACCESS'
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
HTACCESS

If the site loads after this, the old .htaccess had invalid rules. Go to Settings > Permalinks in wp-admin and click "Save" to regenerate proper rewrite rules.

Step 3: Disable All Plugins

A plugin with a fatal PHP error will crash the entire site. If you can't access wp-admin:

# Via WP-CLI:
wp plugin deactivate --all

# Or rename the plugins folder:
mv wp-content/plugins wp-content/plugins-disabled

If the site loads, re-enable plugins one at a time. The one that brings back the 500 is your culprit.

Step 4: Switch to a Default Theme

If plugins aren't the problem, the active theme might have a PHP error:

# Via WP-CLI:
wp theme activate twentytwentyfour

# Or rename the active theme:
mv wp-content/themes/your-theme wp-content/themes/your-theme-disabled

Step 5: Increase PHP Memory Limit

WordPress sites with many plugins, WooCommerce, or page builders often hit the default PHP memory limit:

// In wp-config.php:
define('WP_MEMORY_LIMIT', '256M');

Also update the PHP configuration:

# Find your php.ini:
php -i | grep "Loaded Configuration File"

# Edit and set:
memory_limit = 256M
max_execution_time = 300
post_max_size = 128M
upload_max_filesize = 64M

# Restart PHP-FPM:
sudo systemctl restart php8.2-fpm

Step 6: Check Database Connection

If WordPress can't connect to the database, it will throw a 500 (or sometimes the specific "Error establishing a database connection" page). Verify your database credentials in wp-config.php and test the connection:

# Test MySQL connection with wp-config.php credentials:
mysql -u your_db_user -p -h localhost your_db_name

# Check if MySQL is running:
sudo systemctl status mysql

# If it's down:
sudo systemctl start mysql

Fixing 500 Errors in PHP Applications

For non-WordPress PHP applications (Laravel, Symfony, custom PHP), the debugging approach is similar but the locations differ.

Step 1: Enable Error Display (Development Only)

In development, you can temporarily show errors directly in the browser. Never do this in production because it exposes sensitive information.

# In php.ini:
display_errors = On        # Show errors in browser (dev only!)
error_reporting = E_ALL    # Report all errors
log_errors = On            # Always log errors
error_log = /var/log/php_errors.log

For Laravel specifically, set APP_DEBUG=true in your .env file during development. Laravel's error page will show the full stack trace.

Step 2: Check for Syntax Errors

A PHP syntax error is an instant 500. You can check files without executing them:

# Check a single file:
php -l /path/to/your/file.php

# Check all PHP files in a directory:
find /var/www/html -name "*.php" -exec php -l {} \; 2>&1 | grep "Parse error"

Step 3: Check PHP-FPM Status

If PHP-FPM crashed or all workers are busy, Nginx will return 500 or 502 errors:

# Check PHP-FPM status:
sudo systemctl status php8.2-fpm

# Check PHP-FPM error log:
sudo tail -50 /var/log/php8.2-fpm.log

# Restart if needed:
sudo systemctl restart php8.2-fpm

Step 4: Check for Missing Extensions

A missing PHP extension will cause a fatal error. Common culprits after a PHP version upgrade:

# List installed extensions:
php -m

# Common extensions that applications need:
sudo apt install php8.2-mysql php8.2-curl php8.2-gd php8.2-mbstring php8.2-xml php8.2-zip

# Restart PHP-FPM after installing extensions:
sudo systemctl restart php8.2-fpm

Fixing 500 Errors in Node.js Applications

Node.js applications typically run behind Nginx as a reverse proxy. When the Node.js app throws an unhandled exception, the response is a 500 to the user.

Step 1: Check Application Logs

# If using PM2:
pm2 logs --lines 100
pm2 logs your-app-name --err --lines 50

# If using systemd:
sudo journalctl -u your-app -n 100 --no-pager

Look for unhandled exceptions, rejected promises, or module not found errors.

Step 2: Check If the Process Is Running

# If using PM2:
pm2 status

# If the app shows "errored" or "stopped":
pm2 restart your-app-name

# Check if the expected port is being listened on:
ss -tlnp | grep 3000

Step 3: Check for Missing Dependencies

A common cause of 500 errors after a deploy is missing node_modules:

# Install dependencies:
npm install

# Or if you use a lockfile:
npm ci

# Rebuild native modules if you changed Node.js versions:
npm rebuild

Step 4: Check Environment Variables

Missing environment variables (database URLs, API keys, secrets) are a frequent cause of 500 errors in production. The app starts but crashes on the first request that needs the missing variable.

# Check what environment variables your app sees:
pm2 env your-app-name

# Or check the .env file:
cat /path/to/your/app/.env

# Compare with .env.example to find missing variables:
diff .env .env.example

Fixing 500 Errors in Python Applications

Python web applications (Django, Flask, FastAPI) typically run behind Gunicorn or uWSGI, proxied by Nginx. A 500 error means the Python code raised an unhandled exception.

Step 1: Check Gunicorn/uWSGI Logs

# Gunicorn with systemd:
sudo journalctl -u gunicorn -n 100 --no-pager

# uWSGI logs:
sudo tail -50 /var/log/uwsgi/app.log

# Django debug log (if configured in settings.py):
tail -50 /path/to/project/debug.log

Step 2: Enable Django Debug Mode (Development Only)

In development, Django's debug page shows the full traceback:

# In settings.py (NEVER do this in production):
DEBUG = True

For production, keep DEBUG = False and check the logs instead.

Step 3: Check for Missing Migrations

A common Django 500 is accessing a database table or column that doesn't exist yet:

# Check for unapplied migrations:
python manage.py showmigrations | grep "\[ \]"

# Apply pending migrations:
python manage.py migrate

Step 4: Check for Missing Python Packages

# Activate your virtual environment first:
source /path/to/venv/bin/activate

# Install requirements:
pip install -r requirements.txt

# Restart Gunicorn:
sudo systemctl restart gunicorn

Fixing File Permission Issues

Incorrect file permissions are a silent killer. The web server needs to read your application files, and sometimes write to specific directories (uploads, cache, sessions). If permissions are wrong, you get a 500 with very little explanation in the default error message.

Standard Web Permissions

# Set correct ownership (www-data is the typical web server user):
sudo chown -R www-data:www-data /var/www/html

# Directories should be 755 (read/execute for everyone, write for owner):
sudo find /var/www/html -type d -exec chmod 755 {} \;

# Files should be 644 (read for everyone, write for owner):
sudo find /var/www/html -type f -exec chmod 644 {} \;

Writable Directories

Some directories need write permissions for the web server. Common ones:

# WordPress uploads and cache:
sudo chmod -R 775 wp-content/uploads
sudo chmod -R 775 wp-content/cache

# Laravel storage and cache:
sudo chmod -R 775 storage
sudo chmod -R 775 bootstrap/cache

# Django static and media:
sudo chmod -R 775 staticfiles
sudo chmod -R 775 media

Check the Error Log for Permission Denied

The error log will specifically mention "Permission denied" if this is the cause:

# Search for permission errors:
grep -i "permission denied" /var/log/nginx/error.log
grep -i "permission denied" /var/log/apache2/error.log

How to Prevent 500 Errors

500 errors will happen. Applications have bugs, deployments go wrong, and servers run out of resources. The goal is to catch them fast and have a recovery plan.

Set Up Uptime Monitoring

A 500 error that you catch in 2 minutes is a non-event. A 500 error that runs for 4 hours because nobody checked the site is a business crisis. Uptime monitoring solves this by checking your site continuously and alerting you the moment something goes wrong.

Notifier checks your site and sends alerts via email, SMS, and phone call when it detects any error, including 500s. The free plan includes 10 monitors with 5 minute checks. You'll know about the problem within minutes instead of finding out from an angry customer email.

Add Error Handling in Your Code

Most 500 errors come from unhandled exceptions. Wrap risky operations (database queries, API calls, file operations) in try/catch blocks and return meaningful error responses instead of crashing:

  • PHP: Use try/catch and set a custom error handler with set_exception_handler()
  • Node.js: Handle rejected promises, use process.on('uncaughtException'), and add error middleware in Express
  • Python: Use try/except blocks and configure proper logging with Django/Flask error handlers

Test Deploys Before Production

Use a staging environment that mirrors production. Run your test suite. Do a smoke test on staging before deploying to production. Most 500 errors in production could have been caught with a basic pre-deploy check.

Set Up Centralized Logging

When a 500 error happens at 3 AM, you don't want to SSH into the server and dig through log files. Use a centralized logging tool (Sentry, Logtail, Datadog) that captures errors automatically and sends notifications. Combined with uptime monitoring, this gives you both "something is wrong" (monitoring) and "here's exactly what broke" (logging).

Frequently Asked Questions

Is a 500 error my fault as a visitor?

No. A 500 Internal Server Error is always a server side problem. It means the website's code or configuration is broken. There's nothing wrong with your browser, device, or connection. All you can do is wait and try again later.

What's the difference between a 500 and other 5xx errors?

A 500 means the server's own code crashed (unhandled exception, syntax error, missing file). A 502 means one server couldn't get a valid response from another server. A 503 means the server is overloaded or in maintenance. A 504 means one server timed out waiting for another. The 500 is the most generic: "something broke, but I'm not going to tell you what."

Can a 500 error hurt my SEO?

If it's brief (minutes), no. Google retries pages that return 500 errors. But if your site returns 500 for hours or days, Googlebot will reduce crawl rate and may drop affected pages from the index. The impact is worse than a 503 because a 500 doesn't signal temporary unavailability. Fix the root cause quickly and set up uptime monitoring to catch future incidents before they affect rankings.

Why does my 500 error only happen sometimes?

Intermittent 500 errors are usually caused by resource limits. The code works when the server has capacity, but fails when it's busy. Common culprits: PHP memory limit hit only on heavy pages, database connection pool exhausted under load, or a race condition that only triggers with concurrent requests. Check your error logs with timestamps to correlate the errors with traffic patterns.

My WordPress site just shows a white screen. Is that a 500?

Usually, yes. The "White Screen of Death" in WordPress is most often a 500 error where PHP has crashed before any output was generated. Enable WP_DEBUG and WP_DEBUG_LOG in wp-config.php, then check wp-content/debug.log for the actual PHP error. It's almost always a plugin conflict or a memory limit issue.

How do I know when my site gets a 500 error?

Set up uptime monitoring. Notifier checks your site every minute and alerts you via email, SMS, or phone call when it detects any HTTP error. The free plan covers 10 monitors. Without monitoring, you'll find out about 500 errors from customer complaints, lost sales, or a drop in search rankings.

Should I show the 500 error details to users?

No. Never show detailed error messages, stack traces, or file paths to users in production. This information can expose security vulnerabilities (database credentials, file structure, software versions). Show a friendly error page to users and log the details to a file that only server admins can access.

Get Alerted When Your Site Goes Down

Set up monitoring in 30 seconds. Get email, SMS, and phone call alerts when a 500 or any other error hits your site. Free plan includes 10 monitors.

Start Monitoring Free
Timothy Bramlett

Written by

Timothy Bramlett

Founder, Notifier.so

Software engineer and entrepreneur building tools for website monitoring and uptime tracking.

View author profile