Skip to content
Configuration

WordPress Debug Log Location: Where debug.log Lives and How to Move It

Find debug.log in wp-content, move it outside the web root so visitors cannot fetch it, and fix the WP_DEBUG settings that leave the file empty.

Published

WordPress writes its debug log to wp-content/debug.log by default — an absolute path of /path/to/your/site/wp-content/debug.log on disk. The file does not exist until something is actually logged, and it only gets written at all when WP_DEBUG is true and WP_DEBUG_LOG is enabled in wp-config.php. That default location is also a real security problem, because on most hosts anyone can fetch it in a browser.

The three constants and what each one does

All three go in wp-config.php, above the line that reads /* That's all, stop editing! Happy blogging. */. Anything added below that line runs after WordPress has already booted and is ignored.

ConstantDefaultWhat it does
WP_DEBUGfalseMaster switch. Raises PHP error reporting to show notices, warnings and deprecations. Nothing else on this list works without it.
WP_DEBUG_LOGfalseSends errors to a file. true means wp-content/debug.log. A string is treated as the file path to write to.
WP_DEBUG_DISPLAYtruePrints errors into the page HTML, visible to every visitor.

The dependency is the part people get wrong. WP_DEBUG_LOG is read inside the WP_DEBUG branch of WordPress’s startup code. If WP_DEBUG is false, setting WP_DEBUG_LOG to true does nothing at all — no file, no error, no warning. If you have added WP_DEBUG_LOG and no log appeared, check WP_DEBUG first.

A working live-site configuration:

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );

If WP_DEBUG is already defined further up the file — it usually is, set to false — edit that existing line rather than adding a second define(). Defining the same constant twice throws a PHP warning, which on a site with display enabled lands right at the top of your page.

Why WP_DEBUG_DISPLAY must be false in production

With display on, PHP errors are echoed into the HTML response. A single deprecation notice from a theme prints your server’s absolute filesystem path to every visitor. A database error prints table names and query fragments. Worse, output that appears before headers are sent breaks redirects, breaks REST and AJAX responses that expect clean JSON, and can produce the white screen people then blame on a plugin.

One subtlety worth knowing: setting WP_DEBUG_DISPLAY to null is not the same as false. null tells WordPress to leave PHP’s display_errors setting alone and inherit whatever the server has configured. false actively forces it off. On a production site, use false and add the ini_set line above as a belt-and-braces measure, since a plugin can flip display_errors back on later in the request.

The default location is publicly fetchable

wp-content/debug.log sits inside the web root. Nothing in a stock WordPress install blocks direct requests to it. On a typical Apache or nginx setup, https://yoursite.com/wp-content/debug.log returns the file as plain text. Debug logs contain absolute server paths, plugin and theme internals, database errors with real query text, and sometimes values passed through failing functions. That is free reconnaissance for anyone who guesses the URL — and it is one of the first URLs automated scanners try.

Two ways to deal with it. The better one is to move the log.

Move the log with a path

Since WordPress 5.1, WP_DEBUG_LOG accepts a string file path instead of a boolean. Point it somewhere outside the document root:

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', '/home/youruser/logs/wp-errors.log' );
define( 'WP_DEBUG_DISPLAY', false );

Three rules for that path. Use an absolute path — a relative one is resolved against PHP’s working directory, which varies by request and by server, so you will lose track of where the file went. The directory must already exist; PHP will not create it, and if it cannot open the file it fails silently. And the directory must be writable by the PHP user, which on shared hosting is not the same account you log in with over SFTP.

If your hosting confines you to the web root and there is nowhere above it to write, keep the default path and block access at the server level instead. Apache:

<Files "debug.log">
  Require all denied
</Files>

That goes in a .htaccess file inside wp-content, not the root one — WordPress rewrites the root .htaccess when you save permalinks and can wipe your addition. On nginx, .htaccess does nothing at all; you need a location block in the server config, which on managed hosting usually means asking support.

Be honest about what blocking gets you: the file is still on disk in a directory the web server serves from. A path-traversal bug in any plugin can still read it. Moving it out of the web root is the stronger fix.

Reading and tailing the file

Over SSH, watch it live while you reproduce the bug:

tail -f wp-content/debug.log

Reproduce the error in another tab and the new lines appear as they are written. To see only what has happened recently, or to filter to one plugin:

tail -n 100 wp-content/debug.log
grep -i 'plugin-slug' wp-content/debug.log | tail -n 50

PHP appends to the end of the file, so read from the bottom up. Each entry is timestamped in UTC, which will not match your WordPress timezone setting — do not let that make you think you are looking at old entries.

With WP-CLI you can toggle the constants without editing the file by hand:

wp config set WP_DEBUG true --raw
wp config set WP_DEBUG_LOG true --raw
wp config set WP_DEBUG_DISPLAY false --raw

The --raw flag matters — without it the value is written as the string "true" rather than the boolean. For the path form, drop --raw so it is written as a quoted string.

No SSH? Download the file over SFTP or open it in your host’s file manager. Avoid plugins that surface the log inside wp-admin unless you trust them completely; you are handing a plugin read access to a file full of server internals.

If you want the exact wp-config block for your setup, including a safe out-of-root path and the matching server rule, the WordPress debug log generator will build it for you.

Turn it off when you are done

Nothing in WordPress core rotates or truncates debug.log. On a site throwing a notice on every page load, it grows without limit and can fill the disk — which takes the site down harder than the bug you were chasing. Enable logging, reproduce the problem, read the log, then set WP_DEBUG back to false.

To clear the file without deleting it:

: > wp-content/debug.log

When the log stays empty

Work through these in order. WP_DEBUG is false — the single most common cause, and it silently disables everything else. The constant is below the “stop editing” line in wp-config.php. File permissions — PHP cannot write to wp-content, or to the custom directory you specified. A fatal error before wp-config finishes loading, such as a syntax error in the config file itself, happens too early for WordPress logging to catch; those go to the server’s own PHP error log instead. Your host overrides it — some managed platforms pin PHP’s error_log setting or route logging into their own dashboard, in which case your constants are set correctly and the output is simply somewhere else. Check the host’s log viewer before assuming your config is broken.

FAQ

Questions

Where is the WordPress debug log located?

By default it is wp-content/debug.log, directly inside your wp-content folder. WordPress only creates the file once an error is actually logged, so an empty wp-content folder does not mean logging is broken. If WP_DEBUG_LOG was given a file path instead of true, the log is written to that path instead.

Why is there no debug.log file in wp-content?

Three common reasons. WP_DEBUG is false, so WordPress never switches logging on regardless of WP_DEBUG_LOG. Nothing has errored yet, so the file has not been created. Or PHP cannot write to wp-content because of file permissions. Check the constants first, then permissions.

Can anyone download my WordPress debug.log?

Usually yes. wp-content/debug.log sits inside the web root with no access rules protecting it, so a browser request to that URL often returns the file. Debug logs routinely contain absolute server paths, database errors, and query fragments. Move the log outside the web root or block it in your server config.

What is the difference between WP_DEBUG_LOG and WP_DEBUG_DISPLAY?

WP_DEBUG_LOG writes errors to a file. WP_DEBUG_DISPLAY prints them into the page HTML where visitors can read them. On a live site you want logging on and display off. Both are ignored entirely unless WP_DEBUG is set to true, which is the step most people miss.

How do I read the WordPress debug log?

Over SSH, run tail -f on the log path to watch new entries appear live while you reproduce the problem. Without SSH, download the file over SFTP or open it in your host's file manager. Read from the bottom up, since PHP appends newest entries to the end of the file.

Does enabling WP_DEBUG slow down a live site?

Slightly, and the bigger risk is disk. Verbose logging on a busy site can grow debug.log to gigabytes and fill the disk, which takes the site down. Enable it, reproduce the bug, read the log, then turn it back off. Nothing in WordPress core rotates or truncates that file for you.