One moment your WordPress site is alive. The next it’s a blank white rectangle: no content, no error, no mercy. Customers think you’ve been hacked. Marketing thinks “the internet is down.” You’re staring at nothing, which is arguably worse than a 500 error because at least a 500 admits it’s broken.
This is the White Screen of Death (WSOD). It’s usually not mystical. It’s almost always a PHP fatal error, a memory exhaustion, or a cache/edge layer returning a blank response. The trick is to stop guessing and follow a tight sequence that forces the failure to confess.
Fast diagnosis playbook (what to check first)
If you’re on-call, tired, and your Slack is turning into a crime scene, use this. It’s optimized for time-to-signal. The goal is to identify the bottleneck layer: edge/cache, web server, PHP runtime, database, or WordPress code (plugins/themes).
First: is it really the origin?
- Check from your laptop with cache bypass. If a CDN or reverse proxy is serving a cached blank response, you’ll chase ghosts on the server.
- Hit the origin directly (hosts file, direct IP with Host header, or internal load balancer DNS) to isolate edge problems.
Second: is it an HTTP problem or a PHP problem?
- Look at HTTP status and headers. A 200 with a 0-byte body is often PHP dying after headers, output buffering weirdness, or caching returning an empty object.
- Tail web + PHP logs. You want a fatal error line with a timestamp that matches the blank request.
Third: force WordPress to incriminate itself
- Enable WP_DEBUG + debug.log (carefully) and reproduce once.
- Disable plugins in bulk (directory rename or WP-CLI) and retest.
- Switch to a default theme and retest.
Fourth: the unglamorous stuff
- Memory/limits: PHP memory_limit, max_execution_time, opcache, file permissions, disk full.
- Recent changes: updates, new plugin, new theme, PHP version change, config management run, cache purge policy change.
That’s the playbook. Now let’s do the work with a five-step sequence that produces answers, not vibes.
What WSOD actually is (and why it lies)
WSOD isn’t a single bug. It’s a symptom: your request completed without rendering visible output. That can happen for multiple reasons:
- PHP fatal error before output (or output is suppressed). Often caused by incompatible plugin/theme code, missing classes, or calling a function removed in a newer PHP version.
- Memory exhaustion (classic): “Allowed memory size exhausted”. Sometimes you won’t see it in the browser because display_errors is off.
- Output buffering/caching oddities: a caching layer stores an empty response and happily serves it as “successful”.
- Permission or filesystem failures: WordPress can’t read theme files, can’t write cache, can’t autoload something; the runtime dies.
- Opcode cache issues (less common now, still real): stale opcache after deploys or broken invalidation patterns.
- Edge/CDN problems: not WordPress at all. The “white page” is a placeholder from an intermediate layer.
WSOD lies because browsers are polite. They don’t scream about the empty body; they just render nothing. Your server, however, did scream—into logs, into stderr, into systemd journal—somewhere. Your job is to find where the screaming went.
One quote worth keeping in your head during incidents:
“Hope is not a strategy.” — Gene Kranz
That’s operations in five words: stop hoping it’s “just a cache thing” and start proving which layer is failing.
Joke #1: The White Screen of Death is the only time a blank page counts as “full transparency.”
The 5-step fix that works
Step 1: Confirm the failure mode (status code, body size, cache involvement)
Before you touch WordPress, confirm what clients actually get. If the edge is serving a cached empty response, you’ll fix the origin and still see white until cache expires.
Do: capture headers, status code, content length, and cache headers. Compare origin vs CDN.
Avoid: immediately editing wp-config.php on a hunch. In production, hunches are how you create a second incident.
Step 2: Read the logs like you mean it (web + PHP-FPM + system journal)
WSOD is usually a PHP fatal error. Fatal errors land in PHP-FPM logs, web server error logs, or the system journal depending on how your stack is wired.
Do: tail logs while reproducing the issue once. Time correlation beats archaeology.
Avoid: reading logs from three days ago while your load balancer health checks are hammering new failures every second.
Step 3: Turn on WordPress debug logging (without turning your site into a confession booth)
WordPress can log PHP notices/warnings/fatals into wp-content/debug.log. This is often the cleanest source of truth for plugin/theme failures.
Do: enable logging, disable display in browser, reproduce, then turn it back off.
Avoid: enabling display_errors on a public site. Security teams have feelings too.
Step 4: Remove complexity fast (disable all plugins, switch theme)
Most WSODs are self-inflicted by code running inside WordPress. Plugins and themes are untrusted code with a nice UI. Treat them accordingly.
Do: disable plugins in bulk (rename plugin directory or WP-CLI). Then switch to a default theme (Twenty Twenty-*). Retest after each change.
Avoid: disabling plugins one by one via wp-admin when wp-admin itself is white. That’s not troubleshooting; that’s performance art.
Step 5: Fix the underlying constraint (memory, PHP version, permissions, storage, DB)
Once you know the trigger—plugin incompatibility, missing PHP extension, memory exhaustion, disk full—you apply the real fix. If it’s memory, increase it properly and confirm; if it’s a bad deploy, roll back; if it’s disk, free space and prevent recurrence. Recovery is not the same as prevention.
Now let’s get concrete with commands. Not “try turning it off and on again.” Real tasks, real outputs, real decisions.
Hands-on tasks: commands, outputs, and decisions (12+)
Assumptions for examples below:
- Linux server with Nginx + PHP-FPM (we’ll mention Apache too).
- WordPress lives at
/var/www/wordpress. - You have SSH and sudo.
Task 1: Check HTTP status, headers, and body size (from a shell)
cr0x@server:~$ curl -sS -D - -o /dev/null -w "status=%{http_code} bytes=%{size_download} time=%{time_total}\n" https://example.com/
HTTP/2 200
date: Tue, 04 Feb 2026 10:12:01 GMT
content-type: text/html; charset=UTF-8
cache-control: max-age=0, must-revalidate
cf-cache-status: HIT
status=200 bytes=0 time=0.092
What it means: HTTP 200 but bytes=0. Also a cache header says the CDN served it (HIT).
Decision: Bypass cache / hit origin directly. Don’t touch WordPress yet; you might be looking at a cached empty response.
Task 2: Bypass cache and compare response
cr0x@server:~$ curl -sS -H "Cache-Control: no-cache" -D - -o /dev/null -w "status=%{http_code} bytes=%{size_download}\n" https://example.com/
HTTP/2 500
date: Tue, 04 Feb 2026 10:12:11 GMT
content-type: text/html; charset=UTF-8
status=500 bytes=0
What it means: Cache bypass reveals a 500 at origin (or at least not cached). Good: now you’re chasing a real error.
Decision: Go to logs immediately and reproduce once.
Task 3: Tail Nginx error log while reproducing
cr0x@server:~$ sudo tail -n 50 -f /var/log/nginx/error.log
2026/02/04 10:12:11 [error] 13219#13219: *918 FastCGI sent in stderr: "PHP message: PHP Fatal error: Uncaught Error: Call to undefined function get_field() in /var/www/wordpress/wp-content/themes/custom/functions.php:211" while reading response header from upstream, client: 203.0.113.15, server: example.com, request: "GET / HTTP/2.0", upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:", host: "example.com"
What it means: Theme calls get_field() (Advanced Custom Fields) but the function doesn’t exist—plugin missing/disabled, or loaded too late.
Decision: Disable theme or restore the missing plugin. This is not a database issue. It’s code.
Task 4: Tail PHP-FPM log (or systemd journal) for fatals
cr0x@server:~$ sudo tail -n 50 -f /var/log/php8.2-fpm.log
[04-Feb-2026 10:12:11] WARNING: [pool www] child 22109 said into stderr: "PHP Fatal error: Uncaught Error: Call to undefined function get_field() in /var/www/wordpress/wp-content/themes/custom/functions.php:211"
What it means: Confirms fatal originates in PHP runtime. You now have the file and line number.
Decision: Proceed with theme/plugin isolation (Step 4) and/or roll back the theme change.
Task 5: Check disk space (blank pages sometimes mean “disk full”)
cr0x@server:~$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 80G 79G 200M 100% /
tmpfs 3.8G 2.0M 3.8G 1% /run
What it means: Root filesystem is full. PHP can fail writing sessions, cache files, or logs; WordPress can fail updating autoloaded options; everything gets weird.
Decision: Free space now (logs, old releases, cache), then implement rotation/monitoring. Do not “increase memory” for a disk problem.
Task 6: Find what’s consuming space quickly
cr0x@server:~$ sudo du -xhd1 /var | sort -h
120M /var/cache
1.8G /var/lib
6.5G /var/log
14G /var/www
What it means: Logs are huge. That’s either high traffic, a logging loop, or missing rotation.
Decision: Inspect /var/log and rotate/truncate safely (and fix root cause).
Task 7: Identify top log offenders
cr0x@server:~$ sudo find /var/log -type f -printf "%s %p\n" | sort -n | tail -n 10
2147483648 /var/log/nginx/access.log
1073741824 /var/log/nginx/error.log
536870912 /var/log/php8.2-fpm.log
What it means: Your logs are ballooning. Maybe a bot storm, maybe a redirect loop, maybe debug logging left on.
Decision: Truncate to recover space (short-term), then fix logrotate and noisy errors (long-term).
Task 8: Safe-ish truncation to recover space fast
cr0x@server:~$ sudo sh -c ': > /var/log/nginx/error.log; : > /var/log/php8.2-fpm.log'
What it means: Files are truncated in place (processes keep file handles). This buys breathing room without restarting services.
Decision: Immediately re-check df -h. Then implement rotation. And consider why error.log was 1GB: that’s not “normal.”
Task 9: Enable WordPress debug logging (controlled)
Edit wp-config.php and set these values near the bottom, above “That’s all”:
cr0x@server:~$ sudo sed -n '1,120p' /var/www/wordpress/wp-config.php
<?php
/* ...existing config... */
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
/* That's all, stop editing! Happy publishing. */
What it means: Errors go to wp-content/debug.log, not to the browser.
Decision: Reproduce the WSOD once, then read the debug log. Turn this off after you’ve captured the evidence.
Task 10: Read the WordPress debug log
cr0x@server:~$ sudo tail -n 60 /var/www/wordpress/wp-content/debug.log
[04-Feb-2026 10:12:11 UTC] PHP Fatal error: Uncaught Error: Call to undefined function get_field() in /var/www/wordpress/wp-content/themes/custom/functions.php:211
Stack trace:
#0 /var/www/wordpress/wp-settings.php(595): include()
#1 /var/www/wordpress/wp-config.php(95): require_once('...')
#2 /var/www/wordpress/wp-load.php(50): require_once('...')
#3 /var/www/wordpress/wp-blog-header.php(13): require_once('...')
#4 /var/www/wordpress/index.php(17): require('...')
#5 {main}
thrown in /var/www/wordpress/wp-content/themes/custom/functions.php on line 211
What it means: Confirms theme-level fatal, plugin function missing. Stack trace shows it dies during bootstrap.
Decision: Fix theme dependency or restore required plugin. Fastest recovery: switch to default theme.
Task 11: Disable all plugins via filesystem rename (works even when wp-admin is dead)
cr0x@server:~$ cd /var/www/wordpress/wp-content
cr0x@server:~$ sudo mv plugins plugins.disabled
cr0x@server:~$ ls -l
drwxr-xr-x 2 www-data www-data 4096 Feb 4 10:13 plugins.disabled
drwxr-xr-x 10 www-data www-data 4096 Feb 4 09:50 themes
What it means: WordPress won’t find plugins; it will treat them as deactivated.
Decision: Re-test the site. If it returns, you’ve proven a plugin-related failure. Then re-enable selectively (rename back, or WP-CLI activate one by one).
Task 12: Switch theme without wp-admin (rename current theme folder)
cr0x@server:~$ cd /var/www/wordpress/wp-content/themes
cr0x@server:~$ sudo mv custom custom.disabled
cr0x@server:~$ ls -1
custom.disabled
twentytwentyfour
twentytwentythree
What it means: WordPress will fall back to an available default theme.
Decision: If the site loads now, your theme is the culprit. Keep the default theme temporarily; fix the custom theme offline.
Task 13: Use WP-CLI to mass-disable plugins (cleaner when available)
cr0x@server:~$ cd /var/www/wordpress
cr0x@server:~$ sudo -u www-data wp plugin deactivate --all
Plugin 'akismet' deactivated.
Plugin 'advanced-custom-fields' deactivated.
Success: Deactivated 12 of 12 plugins.
What it means: Plugins are disabled at the WordPress level (database state), not just hidden via filesystem.
Decision: If disabling fixes WSOD, reactivate plugins one at a time until it breaks. Then you have the offender.
Task 14: Check PHP memory limit and current PHP version
cr0x@server:~$ php -v
PHP 8.2.14 (cli) (built: Jan 15 2026 10:20:41) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.14, Copyright (c) Zend Technologies
with Zend OPcache v8.2.14, Copyright (c), by Zend Technologies
cr0x@server:~$ php -i | egrep -i "memory_limit|opcache.enable|max_execution_time" | head
memory_limit => 128M => 128M
max_execution_time => 30 => 30
opcache.enable => On => On
What it means: 128M is often tight for modern WordPress stacks with page builders, heavy plugins, or large autoloaded options.
Decision: If logs show memory exhaustion, increase memory limit in PHP-FPM pool or php.ini (not just wp-config) and re-test.
Task 15: Spot a memory exhaustion fatal in logs
cr0x@server:~$ sudo grep -R "Allowed memory size" -n /var/log/nginx/error.log | tail -n 3
/var/log/nginx/error.log:9921:FastCGI sent in stderr: "PHP message: PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) in /var/www/wordpress/wp-includes/class-wpdb.php on line 2345"
What it means: It’s not a theme bug; it’s memory. WordPress died in database code because PHP ran out of RAM.
Decision: Raise PHP memory limit and investigate what’s consuming memory (plugin loops, huge autoloaded options, giant queries).
Task 16: Check database connectivity quickly (don’t assume, verify)
cr0x@server:~$ mysqladmin -u wpuser -p ping
Enter password:
mysqld is alive
What it means: DB is reachable with provided credentials (at least from this host). WSOD likely isn’t “DB down.”
Decision: Move on to PHP/WordPress code path, unless logs show database errors or timeouts.
Task 17: Verify PHP-FPM is up and listening where Nginx expects
cr0x@server:~$ systemctl status php8.2-fpm --no-pager
● php8.2-fpm.service - The PHP 8.2 FastCGI Process Manager
Loaded: loaded (/lib/systemd/system/php8.2-fpm.service; enabled)
Active: active (running) since Tue 2026-02-04 09:01:22 UTC; 1h 13min ago
cr0x@server:~$ sudo ss -lxn | grep php8.2-fpm.sock
u_str LISTEN 0 4096 /run/php/php8.2-fpm.sock 12345678 * 0
What it means: Service is running, socket is listening. If you still get blanks, it’s likely application-level or permissions on the socket.
Decision: If socket missing, restart PHP-FPM; if permissions wrong, fix ownership/mode. Otherwise, keep digging in logs.
Task 18: Check recent changes (packages, deploys) without lore
cr0x@server:~$ grep -E "upgrade|install" /var/log/dpkg.log | tail -n 8
2026-02-04 08:55:10 upgrade php8.2-fpm:amd64 8.2.13-1 8.2.14-1
2026-02-04 08:55:12 upgrade php8.2-cli:amd64 8.2.13-1 8.2.14-1
2026-02-04 08:55:15 upgrade nginx:amd64 1.24.0-1 1.24.0-2
What it means: PHP and Nginx changed recently. Plugin/theme incompatibilities with PHP versions are a frequent WSOD trigger.
Decision: If this correlates with incident start, consider rolling back PHP update or patching the incompatible plugin/theme.
Three corporate mini-stories from production
Mini-story 1: The outage caused by a wrong assumption
At a mid-sized company with a “WordPress is just marketing” attitude, the platform team migrated the site behind a CDN with aggressive caching. They did a quick smoke test: home page loaded, a couple of internal pages loaded, done. They assumed a 200 response always meant “healthy.”
Two days later, a plugin update introduced a PHP fatal error on a specific template used by campaign landing pages. Origin started returning a 500 with an empty body for those pages. The CDN, configured to cache “successful” responses by status code only, had a bug in a rule: it cached the response even when the body was empty due to a mis-specified condition. Visitors got a clean 200 and a blank page. Monitoring didn’t alert because it checked status code, not content length or a keyword.
The on-call engineer spent an hour restarting services because “it’s WordPress, it’ll come back.” It didn’t. The error was deterministic. Once they bypassed the CDN and checked origin directly, they saw the 500 and the PHP fatal in under a minute.
They fixed it by changing health checks to validate content (a simple HTML marker), adjusting cache rules to avoid caching empty bodies, and making “origin bypass test” step zero in the incident runbook.
Mini-story 2: The optimization that backfired
A large org decided to reduce PHP latency by cranking up OPCache settings and enabling aggressive preloading. The change was rolled out during a routine maintenance window. It looked great: faster TTFB, lower CPU. Everyone celebrated.
Then the white screens started—intermittently. Not every request, just enough to ruin your day. The underlying issue wasn’t WordPress at all; it was deployment mechanics. Their deploy process replaced PHP files in place, and sometimes updated plugin directories while PHP-FPM workers were mid-request. With preloading and opcache settings that reduced file stat checks, some workers executed a mix of old and new code paths. When a class moved, autoloading failed, producing fatal errors that manifested as blank pages.
The fix was boring: stop doing in-place file replacement. Deploy to a new release directory, then switch a symlink atomically. Also, tune OPCache validation for their deploy pattern rather than copying “best settings” from a benchmark blog post.
Performance improvements are real, but “fast” that’s occasionally wrong is just a different kind of down.
Mini-story 3: The boring practice that saved the day
A financial services company ran WordPress for documentation and customer onboarding. Nothing glamorous, but it had real impact. They had a strict rule: every change that could impact runtime had an easy rollback path, and every host had enough logging to debug without SSH acrobatics.
When WSOD hit after a theme update, the on-call didn’t panic. They looked at the dashboard: error budget burn, spikes in PHP-FPM fatals, and a clear log line pointing to a missing function. They rolled back to the previous release directory in seconds by flipping a symlink and reloading PHP-FPM. The site returned immediately.
Then, in daylight hours, they reproduced in staging with the same PHP version and plugin set, fixed the theme’s dependency checks (guarding calls to plugin functions), and redeployed properly. Postmortem was short because the facts were already captured by logs and a change timeline.
It wasn’t heroics. It was the quiet competence of having backups, rollbacks, and telemetry that doesn’t disappear when you need it.
Common mistakes: symptom → root cause → fix
WSOD troubleshooting fails in predictable ways. Here are the usual traps, with concrete remediation.
1) Symptom: Home page is white, but some deep URLs work
Root cause: Theme template or front-page hook triggering a fatal error; sometimes a page builder shortcode on the front page.
Fix: Check logs for fatal tied to the front page request. Switch to a default theme to restore service, then fix the template.
2) Symptom: wp-admin is white, front-end is fine (or vice versa)
Root cause: Admin-only plugin, mu-plugin, or admin hook causing fatal. Or a capability plugin breaking admin initialization.
Fix: Disable all plugins and test wp-admin specifically. Check wp-content/mu-plugins for must-use plugins; they don’t disable like normal ones.
3) Symptom: HTTP 200 with empty body, only through CDN
Root cause: Cached empty response, edge rule misconfiguration, or origin returning chunked response that gets mishandled.
Fix: Bypass CDN and compare. Purge cache for affected paths. Update cache rules to avoid caching empty bodies and validate origin responses.
4) Symptom: White screen after updating PHP version
Root cause: Plugin/theme uses deprecated/removed features, strict typing issues, or incompatible dependencies.
Fix: Identify fatal error line; update or replace plugin/theme; if needed, roll back PHP version temporarily. Don’t “just bump memory.”
5) Symptom: WSOD appears under load, disappears when traffic drops
Root cause: PHP-FPM worker exhaustion, slow DB queries, deadlocks, or external API timeouts causing long requests and cascading failure.
Fix: Check PHP-FPM pool settings and slow logs; check DB slow query log; add timeouts; cache external calls. Scale only after you understand saturation.
6) Symptom: WSOD started after enabling a cache/minify plugin
Root cause: Broken minified JS/CSS isn’t WSOD (it breaks layout). But cache plugins can generate empty cached HTML, or object cache can poison results.
Fix: Clear plugin caches, disable cache plugin, and remove generated cache directories. Confirm response bytes and HTML content, not “looks okay sometimes.”
7) Symptom: Only logged-in users see WSOD
Root cause: User-specific hooks, admin bar, personalized caching conflict, or session handling failure (disk full, permissions).
Fix: Test with a clean browser session. Check session save path and permissions; check disk space; disable plugins that modify auth/session flow.
8) Symptom: WSOD after “small config change” in wp-config.php
Root cause: Syntax error (missing quote/semicolon), encoding/whitespace before <?php, or duplicate constant definitions.
Fix: Run a PHP lint on wp-config.php, restore from known-good copy, and use config management templates instead of hand edits.
Joke #2: Nothing says “enterprise” like a production outage caused by one missing semicolon in a file named wp-config.php.
Checklists / step-by-step plan
Incident checklist: restore service first, then fix properly
- Capture evidence: status code + headers + body size from client and from origin. Save it to your incident notes.
- Tail logs while reproducing once: web server + PHP-FPM. Get the fatal line.
- Enable WP_DEBUG_LOG temporarily if logs aren’t showing enough detail.
- Disable plugins in bulk (rename plugins dir or WP-CLI). Retest.
- Switch to default theme (rename custom theme dir). Retest.
- Fix constraint: memory/disk/permissions/PHP version mismatch/etc.
- Rollback if needed: revert last deploy or restore last known-good backup.
- Turn off debug logging and clean up any temporary changes.
- Write down the root cause and the guardrail to prevent recurrence (monitoring, tests, deployment change).
Plugin isolation checklist (the quick, safe way)
- Disable all plugins.
- Verify site loads (front-end and wp-admin).
- Re-enable plugins one by one, testing after each.
- When it breaks, you found the trigger. Leave it disabled.
- Check for a compatible update; otherwise replace it.
Theme isolation checklist
- Switch to a default theme.
- If site loads, the custom theme is guilty until proven innocent.
- Search theme code for direct calls to plugin functions; guard them with
function_exists(). - Fix in staging with the same PHP version and plugin set.
Permanent prevention checklist (the SRE stuff people skip)
- Health checks validate content, not just HTTP 200.
- Backups are tested (restore drills), not just “enabled.”
- Deployments are atomic (symlink releases), not in-place file swaps.
- Log rotation exists and disk alerts fire before 95% usage.
- Staging matches production in PHP version and critical extensions.
- Pin plugin updates or at least batch them with rollback notes.
Interesting facts and history (because this didn’t start yesterday)
- WordPress began in 2003 as a fork of b2/cafelog; plugin ecosystems grew fast, and so did the blast radius of third-party PHP code.
- The term “White Screen of Death” predates WordPress and was popularized in other ecosystems (notably early Windows and console crashes), but web dev adopted it for blank pages with no errors.
- Early WordPress often ran with display_errors on in shared hosting; modern stacks usually hide errors in browsers, which is safer but makes WSOD feel “silent.”
- PHP 7’s release (2015) was a major performance shift; it also exposed compatibility issues in old plugins/themes, a recurring WSOD trigger during upgrades.
- PHP 8 introduced more strictness and changed error behaviors; code that “worked by accident” can start fatal-ing, especially in older themes.
- WordPress’ plugin loading order matters: mu-plugins load before normal plugins, and themes can execute code early via functions.php—great for flexibility, great for outages.
- Caching can make failures persistent: once an empty response is cached at the edge, you can “fix” the origin and still serve white pages until purge/expiry.
- Disk-full incidents are disproportionately common in WordPress environments because of media uploads, backups stored locally, and verbose logs when things go wrong.
- WSOD isn’t always WordPress: misconfigured PHP-FPM sockets, wrong fastcgi params, or SELinux/AppArmor denials can all manifest as a blank page.
FAQ
1) Why is my WordPress page completely white with no error?
Because errors aren’t displayed by default in production. PHP likely hit a fatal error or memory exhaustion, and output never rendered. Look at web/PHP logs or enable WP_DEBUG_LOG briefly.
2) Is WSOD always a plugin problem?
No. Plugins are common, but themes, mu-plugins, PHP version upgrades, disk-full conditions, and caching layers can all produce the same symptom: nothing.
3) What’s the fastest way to recover when wp-admin is also blank?
Disable plugins by renaming wp-content/plugins, then switch the theme by renaming the active theme directory. This bypasses wp-admin entirely.
4) Should I enable WP_DEBUG on production?
Temporarily, with WP_DEBUG_DISPLAY set to false and WP_DEBUG_LOG true. Capture the error, then turn it off. Leaving debug on long-term can leak sensitive paths and flood disks.
5) I get HTTP 200 but the page is blank. How?
Status codes can lie by omission. A reverse proxy might return 200 with an empty body from cache, or PHP may have sent headers before crashing. Check response body size and cache headers, then compare origin vs edge.
6) I increased memory in wp-config.php but WSOD persists. Why?
Because the effective limit is often set in PHP-FPM pool config or php.ini. Also, not all WSODs are memory-related. Confirm with logs showing “Allowed memory size exhausted” before changing limits.
7) Could a database issue cause WSOD instead of “Error establishing a database connection”?
Yes. Slow queries, locked tables, or timeouts can cascade into PHP-FPM saturation, leading to empty responses. But you should still see timeouts in logs. Verify DB health and check slow logs if load-related.
8) What if disabling plugins and switching theme doesn’t fix it?
Then it’s probably below WordPress: PHP-FPM down, socket mismatch, permissions/SELinux denial, missing PHP extensions, disk full, or a web server config regression. Go back to service status and logs.
9) How do I know if it’s Cloudflare (or another CDN) versus my server?
Compare requests with cache bypass headers and hit the origin directly if possible. If origin returns normal HTML and the CDN returns blank, the edge is the problem—purge or fix caching rules.
10) After recovery, what’s the one prevention step with the best ROI?
Content-validating health checks plus a rollback-able deploy process. Those two turn “mystery white page” into a fast, bounded incident.
Next steps you should actually do
WSOD feels like WordPress being dramatic. It’s really your stack telling you, “I crashed, and you didn’t wire the error output to somewhere convenient.” The fix is not a single magic flag; it’s a repeatable sequence.
- Right now: run the fast diagnosis playbook. Capture status/bytes, bypass cache, tail logs, reproduce once.
- Recover service: disable plugins in bulk, switch to a default theme, or roll back the last deploy.
- Fix root cause: patch/replace the offending plugin/theme, correct PHP version incompatibility, raise memory only when proven, and resolve disk/permission constraints.
- Prevent recurrence: add content-based health checks, ensure log rotation + disk alerts, and adopt atomic deployments with easy rollback.
You don’t need heroics. You need evidence, isolation, and the discipline to stop “optimizing” things you haven’t measured.