Is It Your Host or Your Plugins? How to Prove What Took Your WordPress Site Down

by | Oct 18, 2026 | Web development

If your WordPress site keeps going down for a few minutes at a time, the first answer from most hosting support teams is that a plugin or theme is to blame. Sometimes they’re right. Often the server itself stopped the site, and WordPress had no chance to report anything.

You can usually tell which it is from logs you already have. The examples below come from a client site I look after on shared hosting.

⚡ The short answer

  • A WordPress problem leaves a trace. A PHP fatal error is written to the PHP error log, WordPress shows its “There has been a critical error on this website” page, and the site admin gets an email.
  • A server problem usually doesn’t. If the hosting server stops the PHP process, nothing is logged and no email is sent. Visitors see the web server’s own plain error page instead of WordPress’s, usually a 500, sometimes a 503, 504 or 508.
  • Test more than one kind of page. If the login page, the REST API and your feed fail at the same moment as normal pages, the whole server is struggling, not one plugin.
  • Write down the exact times in UTC. Hosts can only check their own records if you give them precise times.
  • A free snippet can prove PHP started. It writes a line when each request begins and another when it ends. A request that starts and never ends was stopped from outside WordPress.

🔎 What a host-side failure looks like

The client site went down several times over a few months, often in the evening or at night, usually for a few minutes at a time. An uptime monitor caught each one. The host asked for evidence that the site wasn’t causing it.

These were the signs.

The error page was the server’s, not WordPress’s. Every failed request returned a 500 error of about 550 bytes. That’s the web server’s stock page, which ends with “More information about this error may be available in the server error log.” Since version 5.2, a PHP fatal error in WordPress produces its own critical-error page and an email to the admin. Neither appeared.

The PHP error log showed PHP starting, then nothing. This site happened to log a harmless warning at the very start of every request. During one outage there were six failed requests in nine minutes, and each one had that warning at exactly the second it failed. There was no fatal error after any of them. PHP had started, read the configuration and then stopped, without logging anything.

Hardly anyone was visiting. There were only nine requests in the 17 minutes around that outage. Heavy traffic wasn’t the cause.

The host was also turning away traffic. Over two days the server sent more than 900 “429 Too Many Requests” responses, mostly to scanning bots. That is the host’s own rate limiting, and it shows the server was already busy turning traffic away.

Put together, that points at the server. Something outside PHP was stopping the process, such as a resource limit, a hung background job or a server-wide stall.

⚠️ When it really is your site

The same client site had a different outage earlier in the year, and that one was the site’s fault. Every page returned the plain 500 error for about eight hours, overnight and into the morning. The cause was a page builder that hadn’t been updated for years, crashing while it built page content. Updating it fixed the site.

It looked like a host problem at first, because the crash also left no PHP error and showed the server’s plain error page. A PHP process that crashes outright logs nothing, the same as one that’s killed. What told the two apart was testing different kinds of page. During the builder outage, only pages with builder content failed. During the night-time stall, every request in the access log failed, whatever the address.

PageBuilder outage (what I saw)Server-wide stall (what to expect)
Normal pages500500
/wp-login.phpWorked500
/wp-json/ (REST API)Worked500
/feed/Worked500
A missing page (404)Worked500

When only pages built by the theme or builder fail, the problem is in the site. When everything fails at once, including pages that barely touch your theme, it’s the server.

Page size was a second clue. A tiny cookie policy page failed in the same 0.8 seconds as the large home page. If the site had been running out of memory, the big page would have failed first.

🛠️ How to check your own site

  1. Get the exact times. An uptime monitor (several have free plans) records when the site went down and came back. Note them in UTC. Server logs are usually in UTC, and in the summer UK time is an hour ahead.
  2. Download the access log for those days from your hosting control panel or over SFTP. For each failed request, note the time, the address, the status code and the size in bytes. A run of identical small 500 responses is the stock error page.
  3. Check the PHP error log. If your host doesn’t give you one, you can turn on PHP’s own logging in wp-config.php with two lines: @ini_set( 'log_errors', 1 ); and @ini_set( 'error_log', '/path/to/php-errors.log' );. This works even when WP_DEBUG is off. WordPress’s own WP_DEBUG_LOG only works when WP_DEBUG is true.
  4. Look for a fatal error at the failure times. If there is one, it names the plugin or theme file, and the problem is on your side. If there’s nothing, keep going.
  5. Test different kinds of page during the next outage: a normal page, /wp-login.php, /wp-json/, /feed/ and an address that doesn’t exist.
  6. Look at what else was happening. Note how many requests arrived around the failure, whether a backup or update was due, and whether the failures land at the same minutes past the hour.

📋 A snippet that proves PHP started

On most sites PHP doesn’t log anything when a request starts, so step 4 can’t tell “PHP never ran” from “PHP ran and was stopped”. This small must-use plugin fills that gap. It writes one line when WordPress starts handling a request and another when the request ends.

Save it as request-log.php in wp-content/mu-plugins/ (create the folder if it’s missing):

<?php
/**
 * Plugin Name: Request start/end log (temporary)
 */
$request_log  = '/path/outside/public_html/request-log.txt';
$request_id   = substr( md5( uniqid( '', true ) ), 0, 8 );
$request_line = function ( $state ) use ( $request_log, $request_id ) {
	$path = isset( $_SERVER['REQUEST_URI'] ) ? strtok( $_SERVER['REQUEST_URI'], '?' ) : '-';
	$mb   = round( memory_get_peak_usage() / 1048576, 1 );
	error_log( gmdate( 'Y-m-d H:i:s' ) . " $request_id $state {$mb}MB $path\n", 3, $request_log );
};
$request_line( 'START' );
register_shutdown_function( function () use ( $request_line ) {
	$request_line( 'END' );
} );

Change the path to a folder outside your public web folder. Most hosts give you one above public_html. Log files inside wp-content, including WordPress’s own debug.log, can often be downloaded by anyone who guesses the address.

Reading the result:

  • START and END: the request finished normally, even if it showed an error.
  • START with no END: PHP was stopped from outside. Nothing inside WordPress gets to run, not even a shutdown function. Check whether the page builder test above points at your site first.
  • No START at all: the request was stopped before WordPress loaded its plugins, or never reached PHP. The access log shows whether it arrived.

The snippet strips query strings, so it doesn’t record search terms or tracking codes. It writes to disk on every request, so remove it once you have the evidence.

A table comparing a normal request, a PHP fatal error and a request stopped by the server, showing which one ends in a WordPress 500 error page with nothing in the logs.
What a normal request, a PHP fatal error and a stopped request each leave behind.

📨 What to send your host

Keep it short and specific:

  • The exact times of the failures, in UTC.
  • For each one, the address, the status code and the size from the access log.
  • A copy of the error page visitors saw.
  • A line saying the PHP error log has no error at those times, and that the requests started and never finished (if you used the snippet).
  • The page test results, showing that the login page and REST API failed too.
  • A request for their server error log and any resource-limit reports for those exact times. On servers running CloudLinux, these show whether your account hit its CPU, memory or process limits.

Hosts can see things you can’t, such as other accounts on the same server and their own scheduled jobs, and exact times let them check those records.

❓ Frequently asked questions

Does a 500 error always mean a plugin is broken?
No. A 500 error only means the server couldn’t complete the request. A PHP fatal error from a plugin is one cause, and WordPress normally reports it. A process stopped by the server is another, and WordPress can’t report that.

My host says I’m hitting resource limits. Is that my fault?
It can be. A slow plugin or a busy shop can use more than a cheap plan allows. The access log shows how many requests arrived at the time. If the site fails when it’s quiet, the limit isn’t being reached through your visitors.

Will a caching plugin fix it?
It reduces the load, but a caching plugin runs on the same server. If the whole server stalls, cached pages stop too. Caching at a CDN, outside the server, can keep pages showing during a short stall.

Should I just move host?
If the evidence points at the server and the host can’t fix it, moving is reasonable. Take the logs with you. They’re also useful for checking the new host does better.

🧪 Should this be a plugin?

I’m considering turning the snippet into a small plugin. It would record requests that start and never finish, line them up with your uptime monitor, and produce a report you can send to your host. If that would help you, let me know through the comments.

Sources

Checked on 18 October 2026.

Tags:

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

Pin It on Pinterest