WP_DEBUG in production: why it is dangerous and what to use instead

Debug mode in production exposes file paths, versions and code internals to every visitor. Safe disable with private logging preserved.

WP_DEBUG is the WordPress development mode that makes every PHP error, warning or notice render directly inside the page HTML. In a development environment it is essential. In production it is a serious security mistake that exposes the site in several ways at once.

Why this matters

WP_DEBUG enabled in production produces three concrete problems. Information disclosure - a typical error reveals the full server path ('/var/www/html/wp-content/plugins/X/inc/Y.php on line 123'), plugin name, PHP version, and sometimes variables from code that contain sensitive data. An attacker uses this to map the install, identify a vulnerable version, or learn internal filenames that can be abused in an LFI attack. Broken user experience - PHP notices instead of content, or at the top of the page, look unprofessional, erode trust and break payment flows when the error precedes header(). SEO impact - Google indexes PHP errors as page content, hurting quality scores. On top of all that, every PHP error - even a minor notice - costs CPU. A site producing hundreds of notices per page runs 15-30% slower than necessary.

How to detect

The audit reads wp-config.php and checks the WP_DEBUG value. If it is true, the check is red. Manually: open wp-config.php and search for WP_DEBUG. A line like define('WP_DEBUG', true); is the problem. Also check WP_DEBUG_DISPLAY: even with WP_DEBUG true, display to the visitor should be false. A practical test: open a random page with an invalid query parameter ('?page=)(asdf=)' or similar) - if you see PHP errors, debug is on.

How to fix

  1. Edit wp-config.php over FTP/SFTP or File Manager.
  2. Find define('WP_DEBUG', true); - set it to false or remove the line.
  3. Add the recommended production settings:
    define('WP_DEBUG', false);
    define('WP_DEBUG_LOG', false);
    define('WP_DEBUG_DISPLAY', false);
    @ini_set('display_errors', 0);
  4. If you do need to track errors without showing them to visitors:
    define('WP_DEBUG', true);
    define('WP_DEBUG_LOG', true);    // writes to wp-content/debug.log
    define('WP_DEBUG_DISPLAY', false); // hides from visitors
    @ini_set('display_errors', 0);
  5. If you keep WP_DEBUG_LOG on, make sure debug.log is not reachable over HTTP - add to .htaccess:
    <Files debug.log>
        Require all denied
    </Files>
  6. Save wp-config.php and upload it. Reload the site in a private window.
  7. Browse a few pages. There should be no PHP errors anywhere on screen.

Common mistakes

Do not leave WP_DEBUG_DISPLAY on 'just for a few days' - admins forget. Do not write errors to debug.log without protecting the file - a debug.log served over HTTP exposes the very information you tried to hide. Do not ignore 'Cannot modify header information' messages that linger after the change - they come from somewhere else (usually whitespace at the start of a functions.php file). Do not enable WP_DEBUG in production 'just to see what is wrong' without setting WP_DEBUG_DISPLAY to false first - you are publishing the problem to the world.

Verifying the fix

Open the site in a private window and reload 5-10 different pages. No PHP errors anywhere. Try pages with forms, comments and checkout. View source - there should be no lines starting with 'Notice:', 'Warning:', 'Deprecated:', 'Fatal error:'. If you kept WP_DEBUG_LOG on, watch that debug.log does not grow at an unusual rate.

Tip: If debug.log grows fast (over 5 MB per week), the site is throwing errors at scale. Run Query Monitor (free plugin) on staging to find the source - usually an old plugin with PHP-8-incompatible syntax.