← Back to blog

Debugging a WordPress white screen when you cannot get into wp-admin

The SandyWP team 7 min read

A blank WordPress page is almost always a fatal PHP error that you are not being shown. Nothing is broken about the display: PHP died mid-request, and both PHP and WordPress are configured to keep the reason to themselves.

So debugging it is not a hunt for a fix. It is a sequence of steps to make the error visible again, in the cheapest order, without experimenting on a site people are using.

Why the page is blank in the first place

Two separate settings have to line up before you see nothing at all.

The first is PHP's display_errors, which production hosts turn off deliberately. Error text can contain absolute paths, database names, and query fragments, so leaking it to visitors is a real risk.

The second is WordPress. WP_DEBUG "is assumed to be false by default", and WP_DEBUG_DISPLAY only has an effect once debugging is on (WordPress advanced administration handbook).

With both off, a fatal error produces an empty response body and a 500 status. The white screen is the absence of a message, not a message in itself.

That is also why "white screen" is a misleading name. Check the HTTP status code before anything else, because a 500 points at PHP, while a 200 with an empty body usually points at a theme template or an output-buffering problem instead.

Check your email before you touch anything

Since WordPress 5.2, a fatal error triggers recovery mode. WordPress emails the administrator address with a secret link, and that link gives you a session where "plugins and themes which are causing a fatal error are paused for that client" (Make WordPress Core, 2019-04-16).

Almost none of the popular white-screen guides mention this, and it is the fastest route back into wp-admin when it works. Search the admin inbox for a message titled around your site having a technical issue.

Four things stop that email arriving, and each is a useful clue on its own:

  • The admin email address in Settings is wrong, or the site cannot send mail at all.
  • The fatal error happens before WordPress registers its shutdown handler, so nothing catches it. A syntax error in wp-config.php or in a must-use plugin lands here.
  • Someone set WP_DISABLE_FATAL_ERROR_HANDLER in wp-config.php, which turns the whole mechanism off.
  • The site ran out of memory. The handler needs memory to run too.

Recovery mode is also per-client, tied to the cookie rather than to your user account. Other visitors still see the broken site, so it buys you access, not a fix.

Read the log, not the page

If recovery mode is not an option, stop trying to make the browser show you the error and go to the file where it was already written.

Add this to wp-config.php, above the line that says to stop editing:

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );

That combination logs everything to wp-content/debug.log and shows nothing to visitors, which is the only version of this that is safe to run on a site that is publicly reachable. Reload the broken URL once, then read the last few lines of the file.

If debug.log is empty or does not exist, check the PHP error log instead. Errors that happen before WordPress boots never reach debug.log, and on most hosts the PHP-FPM log is where they land.

Turn all three constants back off when you are done. Leaving WP_DEBUG on in production is a slow leak of information and a growing file nobody rotates.

No admin access, no log, no idea

When you cannot log in and the log tells you nothing, the classic bisection still works and still takes about five minutes over SFTP or a file manager.

Rename wp-content/plugins to wp-content/plugins-off. WordPress cannot find the plugin files, deactivates all of them, and usually gives you the site back. Rename the folder back, then reactivate one plugin at a time from wp-admin until the screen goes blank again.

If plugins are not it, rename the active theme's folder. WordPress falls back to a default theme if one is installed, which is a good reason to keep one installed.

Memory exhaustion is the other common cause, and it looks identical from the browser. Raising the limit in wp-config.php with define( 'WP_MEMORY_LIMIT', '256M' ); is worth one attempt, but treat a site that needs more than 256MB to render a page as a bug to find rather than a number to keep raising.

Do the actual debugging on a copy

Everything above is triage on a live site, and triage is where most people stop. The problem is that the interesting question is usually not "how do I get the site back", it is "what exactly broke, and will my fix hold".

You cannot answer that on production. Turning on visible errors, deactivating plugins one at a time, and switching PHP versions are all things that affect real visitors while you do them.

A disposable copy removes that constraint. With SandyWP you install the Cloner plugin on the source site and it packages the site and uploads it, and SandyWP restores it as a normal sandbox with the same plugins, the same theme, and the same database. The read is one-way, so the copy cannot write back to production.

In the copy, the same steps stop being risky:

  • Debug mode is a per-site toggle for WP_DEBUG, WP_DEBUG_LOG, WP_DEBUG_DISPLAY, and SCRIPT_DEBUG, with a debug.log viewer next to the toggles. No wp-config.php editing, no FTP client.
  • Turning WP_DEBUG_DISPLAY on is now reasonable, because the only visitor is you. The error appears on the page instead of in a file.
  • The File Manager gives you the file tree and an editor in the browser, so renaming the plugins folder is a two-click operation.
  • PHP 7.4, 8.1, 8.2, and 8.3 are switchable per sandbox, and switching leaves the files and database alone. If a site died the morning after a host upgraded PHP, this is how you confirm it in one minute.

That last one is worth dwelling on. A large share of sudden white screens are not caused by anything anyone changed on the site: they are a plugin using something that a newer PHP version removed. Flipping the copy back to the old version and watching the site return is a definitive answer, and it also tells you the fix is a plugin update rather than a rollback.

What a copy will not tell you

Being honest about this matters, because a sandbox that quietly differs from production will send you down a wrong path.

A copy will not reproduce anything caused by load. Fatal errors that only appear under concurrency, or that come from a request timing out at the web server, need the real traffic.

It will not reproduce host behaviour either. Object caching, an edge cache, a WAF rule, open_basedir restrictions, and OPcache serving a stale compiled file are all outside the site's own files, and OPcache in particular can keep a site broken after the bad file has already been fixed.

It also will not reproduce anything bound to your domain. Licensed pro plugins, real payment gateways, and OAuth callbacks may behave differently on a sandbox URL, and a plugin that refuses to run without a valid licence can itself be the fatal error you are chasing.

For those, use staging on the same host, or fix forward on production with a maintenance window. A sandbox is the right tool for code and data problems, not for infrastructure ones.

The order, condensed

  1. Check the HTTP status code. 500 means PHP; 200 with an empty body means theme or output.
  2. Check the admin inbox for the WordPress recovery mode email.
  3. Enable WP_DEBUG and WP_DEBUG_LOG with WP_DEBUG_DISPLAY off, reload once, read wp-content/debug.log.
  4. If that is empty, read the PHP error log.
  5. Rename wp-content/plugins, then the theme folder.
  6. Try one memory-limit increase, and treat anything above 256MB as suspicious.
  7. Clone the site and do the real diagnosis there, with visible errors and PHP version switching.
  8. Turn every debug constant back off on production.

Steps 1 to 6 get the site back. Step 7 is the one that stops it happening again in a fortnight, and it is the step that is hard to justify without a copy you are allowed to break.