DEV Community

WP Multitool
WP Multitool

Posted on • Edited on • Originally published at wpmultitool.com

The Complete wp-config.php Guide: Every Constant WordPress Developers Should Know

The File That Can Kill Your Site in One Keystroke

Every WordPress installation has exactly one file where a single missing semicolon takes down the entire site. No error message. No admin panel. No recovery path from the browser. Just a white screen, or if you're lucky, a cryptic PHP parse error that only appears if display_errors happens to be on.

That file is wp-config.php.

I've been working with WordPress for over 15 years, and I still treat this file with respect every time I open it. Not because it's complex — it's actually one of the simplest files in the codebase. It's just a list of PHP constants. But it's loaded before everything else, before WordPress core, before any error handling, before any plugin that might catch problems gracefully. If wp-config.php has a syntax error, nothing runs. Nothing.

And yet, the standard advice in every WordPress tutorial is "just open wp-config.php and add this line." As if hand-editing a file that can instantly brick your site is no big deal.

This guide is the reference I wish existed when I started. Every constant explained, organized by purpose, with the actual values you should use and the mistakes that will get you a 3 AM phone call from a panicking client.

What wp-config.php Actually Does

When a request hits your WordPress site, wp-config.php is the first file that executes. It runs before wp-settings.php, before any plugin loads, before the theme initializes. It defines the constants that control everything downstream.

Here's the loading order:

  1. Web server receives request, starts PHP
  2. wp-config.php loads — defines database credentials, security keys, and behavior constants
  3. wp-config.php includes wp-settings.php
  4. wp-settings.php bootstraps WordPress core
  5. Plugins load
  6. Theme loads
  7. Template renders

Because wp-config.php runs first, it controls things that can't be changed later. Once a PHP constant is defined with define(), it can't be redefined. A plugin can't override your WP_DEBUG setting. A theme can't change your database credentials. Whatever you put in wp-config.php is final.

The file also serves as the connection between WordPress and your specific environment — your database, your server paths, your security configuration. Two identical WordPress installations can behave completely differently based solely on their wp-config.php files.

WordPress loading order flowchart showing wp-config.php position with syntax error warning

The Anatomy of wp-config.php

A default wp-config.php has a specific structure, and the order matters more than people realize. Here's the skeleton:

<?php
// ** Database settings ** //
define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'root' );
define( 'DB_PASSWORD', 'password' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );

// ** Authentication keys and salts ** //
define( 'AUTH_KEY',         'unique-phrase-here' );
define( 'SECURE_AUTH_KEY',  'unique-phrase-here' );
define( 'LOGGED_IN_KEY',    'unique-phrase-here' );
define( 'NONCE_KEY',        'unique-phrase-here' );
define( 'AUTH_SALT',        'unique-phrase-here' );
define( 'SECURE_AUTH_SALT', 'unique-phrase-here' );
define( 'LOGGED_IN_SALT',   'unique-phrase-here' );
define( 'NONCE_SALT',       'unique-phrase-here' );

// ** Table prefix ** //
$table_prefix = 'wp_';

// ** Custom constants go HERE ** //

/* That's all, stop editing! Happy publishing. */

/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
    define( 'ABSPATH', __DIR__ . '/' );
}

/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';
Enter fullscreen mode Exit fullscreen mode

The critical line is the comment: /* That's all, stop editing! Happy publishing. */

Every custom constant you add must go ABOVE that line. Below it, wp-settings.php gets included and WordPress starts bootstrapping. If you define a constant after require_once ABSPATH . 'wp-settings.php', WordPress has already loaded without your setting. The constant technically exists, but WordPress already made its decisions without it.

I see this mistake at least once a month. Someone adds define( 'WP_DEBUG', true ); at the very bottom of the file, below the require_once line, and wonders why debug mode isn't working. The constant is defined — but WordPress already checked for it and moved on.

Debugging Constants

These are the constants you'll reach for most often during development and troubleshooting.

WP_DEBUG

define( 'WP_DEBUG', true );
Enter fullscreen mode Exit fullscreen mode

The master switch for WordPress debugging. When true, WordPress displays PHP errors, notices, and warnings that are normally suppressed. This is the first thing I enable when diagnosing any WordPress problem.

On a production site, WP_DEBUG should always be false. PHP notices reveal file paths, function names, and sometimes database structure — information that helps attackers. But on staging or development, it should always be true.

WP_DEBUG_LOG

define( 'WP_DEBUG_LOG', true );
Enter fullscreen mode Exit fullscreen mode

When enabled alongside WP_DEBUG, WordPress writes all debug output to wp-content/debug.log. This is essential for catching errors on production without displaying them to visitors. You can also set it to a custom path:

define( 'WP_DEBUG_LOG', '/var/log/wordpress/debug.log' );
Enter fullscreen mode Exit fullscreen mode

I keep a custom log path on every production site I manage. The default wp-content/debug.log is web-accessible unless you block it with .htaccess or nginx rules. A log file outside the webroot is safer.

WP_DEBUG_DISPLAY

define( 'WP_DEBUG_DISPLAY', false );
Enter fullscreen mode Exit fullscreen mode

Controls whether debug output shows up on screen. The production debugging combo I use on every site:

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );
Enter fullscreen mode Exit fullscreen mode

This captures every error in the log file without showing anything to visitors. The @ini_set line is a safety net — it suppresses display at the PHP level in case any code re-enables it.

SCRIPT_DEBUG

define( 'SCRIPT_DEBUG', true );
Enter fullscreen mode Exit fullscreen mode

Forces WordPress to load the unminified versions of core CSS and JavaScript files. Useful when you're debugging core behavior or developing against WordPress's bundled scripts (like jQuery, wp.media, or the block editor). On production, leave this false — the minified versions are smaller and faster.

SAVEQUERIES

define( 'SAVEQUERIES', true );
Enter fullscreen mode Exit fullscreen mode

Makes WordPress store every database query, along with how long it took and which function called it, in the global $wpdb->queries array. This makes detailed query data available to tools like Query Monitor for backtraces and timing analysis.

Never enable this on production. It stores every query in PHP memory for the lifetime of the request. On a page that runs 400 queries, that's a significant chunk of RAM. It also adds a backtrace call for every query, which slows things down further. Use it for debugging, then turn it off.

WP_DISABLE_FATAL_ERROR_HANDLER

define( 'WP_DISABLE_FATAL_ERROR_HANDLER', true );
Enter fullscreen mode Exit fullscreen mode

WordPress 5.2+ includes a fatal error recovery mode that catches fatal errors and shows a "There has been a critical error on this website" message. This is helpful for users but annoying for developers because it hides the actual error. Setting this to true shows the raw PHP error instead, which is what you want when debugging.

Split view showing browser with normal page and debug.log capturing errors silently

Security Constants

These constants harden your WordPress installation. On any production site, most of these should be enabled.

DISALLOW_FILE_EDIT

define( 'DISALLOW_FILE_EDIT', true );
Enter fullscreen mode Exit fullscreen mode

Removes the built-in theme and plugin code editors from the WordPress admin (Appearance > Theme File Editor and Plugins > Plugin File Editor). This is a must on production. If an attacker gains admin access, the first thing they do is use the theme editor to inject malicious code. Disabling the editor forces them to need FTP/SSH access, which is a much higher bar.

DISALLOW_FILE_MODS

define( 'DISALLOW_FILE_MODS', true );
Enter fullscreen mode Exit fullscreen mode

Goes further than DISALLOW_FILE_EDIT — it also disables the ability to install, update, or delete plugins and themes from the admin panel. This is appropriate for locked-down production environments where deployments happen through Git or CI/CD pipelines.

Be aware: this also blocks automatic WordPress core updates. If you enable this, you need another mechanism for keeping WordPress, plugins, and themes updated. WP-CLI handles this well:

wp core update
wp plugin update --all
wp theme update --all
Enter fullscreen mode Exit fullscreen mode

FORCE_SSL_ADMIN

define( 'FORCE_SSL_ADMIN', true );
Enter fullscreen mode Exit fullscreen mode

Forces the WordPress admin area and login page to use HTTPS. In 2026, your entire site should be on HTTPS already, but this constant is a safety net — even if someone accesses http://yoursite.com/wp-admin, they get redirected to the secure version. Login credentials never travel unencrypted.

Authentication Keys and Salts

define( 'AUTH_KEY',         'put-your-unique-phrase-here' );
define( 'SECURE_AUTH_KEY',  'put-your-unique-phrase-here' );
define( 'LOGGED_IN_KEY',    'put-your-unique-phrase-here' );
define( 'NONCE_KEY',        'put-your-unique-phrase-here' );
define( 'AUTH_SALT',        'put-your-unique-phrase-here' );
define( 'SECURE_AUTH_SALT', 'put-your-unique-phrase-here' );
define( 'LOGGED_IN_SALT',   'put-your-unique-phrase-here' );
define( 'NONCE_SALT',       'put-your-unique-phrase-here' );
Enter fullscreen mode Exit fullscreen mode

These eight constants add randomness to the hashing of passwords and authentication cookies. Each one should be a long, random, unique string. WordPress provides a generator:

https://api.wordpress.org/secret-key/1.1/salt/
Enter fullscreen mode Exit fullscreen mode

Or via WP-CLI:

wp config shuffle-salts
Enter fullscreen mode Exit fullscreen mode

If you ever suspect your site has been compromised, changing these salts immediately invalidates all existing login cookies, forcing every user (including any attacker who's logged in) to re-authenticate.

COOKIE_DOMAIN

define( 'COOKIE_DOMAIN', 'example.com' );
Enter fullscreen mode Exit fullscreen mode

Sets the domain for WordPress cookies. Useful in multisite or when you want cookies to work across subdomains. Setting it to .example.com (with the leading dot) makes cookies available to all subdomains.

WP_HTTP_BLOCK_EXTERNAL

define( 'WP_HTTP_BLOCK_EXTERNAL', true );
define( 'WP_ACCESSIBLE_HOSTS', 'api.wordpress.org,downloads.wordpress.org' );
Enter fullscreen mode Exit fullscreen mode

Blocks all outgoing HTTP requests from WordPress except to the hosts you explicitly allow. This is a strong security measure for sites that don't need to communicate with external services. The WP_ACCESSIBLE_HOSTS constant whitelists specific domains — you'll almost always want api.wordpress.org for updates and security checks.

Performance Constants

WP_MEMORY_LIMIT

define( 'WP_MEMORY_LIMIT', '256M' );
Enter fullscreen mode Exit fullscreen mode

Sets the maximum memory PHP can use during a frontend WordPress request. The default is 40MB for single sites and 64MB for multisite. For any site with WooCommerce, page builders, or more than a dozen plugins, 256MB is a reasonable setting.

This is NOT the same as PHP's own memory_limit in php.ini. WordPress uses WP_MEMORY_LIMIT to call ini_set('memory_limit') during bootstrap. If PHP's memory_limit is lower than WP_MEMORY_LIMIT, WordPress will try to increase it. If your host has set a hard limit via PHP-FPM, WordPress can't exceed it regardless of what you put here.

WP_MAX_MEMORY_LIMIT

define( 'WP_MAX_MEMORY_LIMIT', '512M' );
Enter fullscreen mode Exit fullscreen mode

The memory limit for WordPress admin pages. Admin operations like plugin updates, media uploads, and database exports need more memory than frontend page rendering. The default is 256MB. If you're seeing "Allowed memory size exhausted" errors in the admin, increase this.

DISABLE_WP_CRON

define( 'DISABLE_WP_CRON', true );
Enter fullscreen mode Exit fullscreen mode

Disables WordPress's built-in pseudo-cron system. By default, WordPress checks for scheduled tasks on every page load by spawning an asynchronous request to wp-cron.php. On low-traffic sites, tasks might not run often enough. On high-traffic sites, you're wasting resources checking the schedule on every request.

The better approach is a real server cron job:

# Run WordPress cron every 5 minutes via system cron
*/5 * * * * cd /var/www/html && wp cron event run --due-now --quiet
Enter fullscreen mode Exit fullscreen mode

Or if WP-CLI isn't available:

*/5 * * * * wget -q -O - https://yoursite.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1
Enter fullscreen mode Exit fullscreen mode

WP_POST_REVISIONS

define( 'WP_POST_REVISIONS', 5 );
Enter fullscreen mode Exit fullscreen mode

Limits the number of post revisions WordPress stores. By default, WordPress keeps every revision indefinitely. On a site that's been running for three years with active editors, I've seen wp_posts tables with 200,000+ revision rows. Each revision is a full copy of the post content in the database.

Set this to a reasonable number. 5 gives you enough history to undo mistakes without bloating the database. Set it to false to disable revisions entirely (I wouldn't — they've saved me too many times).

AUTOSAVE_INTERVAL

define( 'AUTOSAVE_INTERVAL', 120 );
Enter fullscreen mode Exit fullscreen mode

How often (in seconds) WordPress autosaves posts while you're editing. The default is 60 seconds. Each autosave fires an AJAX request that triggers a partial WordPress bootstrap. If you have multiple editors working simultaneously, that's a lot of background requests. Setting it to 120 or 180 seconds reduces server load without meaningfully increasing the risk of lost work.

EMPTY_TRASH_DAYS

define( 'EMPTY_TRASH_DAYS', 14 );
Enter fullscreen mode Exit fullscreen mode

Number of days before trashed posts are permanently deleted. Default is 30. Set to 0 to disable trash entirely (items delete immediately — not recommended). I usually set this to 14 days to keep the database cleaner.

WP_CACHE

define( 'WP_CACHE', true );
Enter fullscreen mode Exit fullscreen mode

Enables the advanced caching mechanism. When true, WordPress looks for wp-content/advanced-cache.php and loads it early in the bootstrap process. This is how page caching plugins like WP Rocket and WP Super Cache hook in — they drop their caching logic into advanced-cache.php and rely on this constant being true.

You usually don't set this manually. Caching plugins add it automatically during activation. But if you're debugging caching issues and want to temporarily disable the page cache without deactivating the plugin, setting this to false does the trick.

Compression Constants

define( 'COMPRESS_CSS', true );
define( 'COMPRESS_SCRIPTS', true );
define( 'ENFORCE_GZIP', true );
Enter fullscreen mode Exit fullscreen mode

These enable gzip compression for CSS and JavaScript served through WordPress's built-in script loader (load-scripts.php and load-styles.php). These primarily affect the admin dashboard, since frontend assets are usually handled by your web server's gzip configuration or a caching plugin.

Content and URL Constants

WP_SITEURL and WP_HOME

define( 'WP_SITEURL', 'https://example.com' );
define( 'WP_HOME', 'https://example.com' );
Enter fullscreen mode Exit fullscreen mode

Hardcodes the WordPress address and site address instead of pulling them from the wp_options table. This is useful in two scenarios:

  1. Migration recovery. If you've moved your site to a new domain and can't access the admin because the URLs in the database still point to the old domain, setting these constants overrides the database values and lets you log in.

  2. Performance. Every WordPress request queries wp_options for siteurl and home. Hardcoding them in wp-config.php skips those queries. It's a micro-optimization, but on high-traffic sites, every query matters.

Important: WP_SITEURL is where WordPress core files live. WP_HOME is the URL visitors type to reach your site. They're often the same, but they can differ if you've installed WordPress in a subdirectory.

WP_CONTENT_DIR and WP_CONTENT_URL

define( 'WP_CONTENT_DIR', '/var/www/html/content' );
define( 'WP_CONTENT_URL', 'https://example.com/content' );
Enter fullscreen mode Exit fullscreen mode

Moves the wp-content directory to a custom location. Some security guides recommend this because it breaks automated attacks that assume default WordPress paths. It also allows you to keep WordPress core files separate from your custom content for cleaner upgrades.

WP_DEFAULT_THEME

define( 'WP_DEFAULT_THEME', 'flavor' );
Enter fullscreen mode Exit fullscreen mode

Sets the fallback theme. If the active theme breaks, WordPress falls back to this. By default it's one of the Twenty-* themes. On client sites, I set this to a known-good theme that's always installed.

Database Constants

DB_CHARSET

define( 'DB_CHARSET', 'utf8mb4' );
Enter fullscreen mode Exit fullscreen mode

Sets the character set for the database. utf8mb4 is the correct setting for any modern WordPress installation — it supports the full range of Unicode characters including emoji. If you see utf8 here on an older site, consider migrating to utf8mb4. The utf8 charset in MySQL only supports 3-byte characters, which means it silently truncates emoji and some Asian characters.

DB_COLLATE

define( 'DB_COLLATE', '' );
Enter fullscreen mode Exit fullscreen mode

The database collation (sorting rules). Leave this empty unless you have a specific reason to set it — WordPress will pick the best available collation for your character set (typically utf8mb4_unicode_520_ci). Setting this incorrectly can cause comparison and sorting issues across different languages.

Custom Table Prefix

$table_prefix = 'wp_';
Enter fullscreen mode Exit fullscreen mode

Note this is a variable assignment ($table_prefix), not a define() constant. It sets the prefix for all WordPress database tables. Changing it from the default wp_ is a minor security measure — it prevents SQL injection attacks that assume default table names. But if you're changing this on an existing site, you need to rename every table in the database to match. It's primarily useful during initial installation.

wp-config.php quick reference cheat sheet with debug security performance and content constants

Common Mistakes That Break Sites

I've fixed hundreds of white-screened WordPress sites over the years. These are the mistakes I see again and again.

1. Putting Constants Below "That's All, Stop Editing!"

This is the most common mistake. Someone adds a constant at the bottom of wp-config.php, below require_once ABSPATH . 'wp-settings.php';. The constant gets defined after WordPress has already loaded. Depending on the constant, it either does nothing (WordPress already used its default value) or causes a redefinition warning.

The fix: Always add custom constants between the salts section and the /* That's all, stop editing! */ comment.

2. Missing Semicolons

// This kills the site
define( 'WP_DEBUG', true )

// This works
define( 'WP_DEBUG', true );
Enter fullscreen mode Exit fullscreen mode

A missing semicolon at the end of a define() call causes a PHP parse error. Because wp-config.php loads before WordPress's error handling, there's no graceful fallback. The site outputs a white screen or a raw PHP error.

3. Unclosed Quotes

// This kills the site
define( 'WP_SITEURL', 'https://example.com );

// This works
define( 'WP_SITEURL', 'https://example.com' );
Enter fullscreen mode Exit fullscreen mode

A missing closing quote causes PHP to consume everything until it finds a matching quote — which might be on a completely different line, causing cascading errors that are hard to diagnose.

4. Smart Quotes from Copy-Paste

// These curly quotes kill the site (copied from WordPress blogs or Word docs)
define( 'WP_DEBUG', true );

// These straight quotes work
define( 'WP_DEBUG', true );
Enter fullscreen mode Exit fullscreen mode

This one is infuriating because it's invisible at a glance. If you copy code from a blog post, WordPress itself sometimes converts straight quotes to curly quotes for typography. Paste that into wp-config.php and PHP doesn't recognize them as valid string delimiters.

Always type constants by hand, or paste into a code editor (VS Code, Sublime) that will flag invalid characters. Never paste PHP code from a CMS-rendered blog post directly into a config file.

5. Redefining an Existing Constant

define( 'WP_DEBUG', true );
// ... 50 lines later ...
define( 'WP_DEBUG', false );  // PHP notice: constant already defined
Enter fullscreen mode Exit fullscreen mode

In PHP 7.x, redefining a constant throws a notice. In PHP 8.x+, it throws a warning. Either way, the second define() is silently ignored — the first value wins. On a long wp-config.php with many edits over the years, it's easy to add a duplicate without noticing.

Search your file before adding anything: does this constant already exist?

6. Wrong Value Types

// Wrong — string 'true' is NOT boolean true
define( 'WP_DEBUG', 'true' );

// Correct — boolean true, no quotes
define( 'WP_DEBUG', true );

// Wrong — string '5' works but is sloppy
define( 'WP_POST_REVISIONS', '5' );

// Correct — integer 5
define( 'WP_POST_REVISIONS', 5 );
Enter fullscreen mode Exit fullscreen mode

PHP is loosely typed enough that string 'true' evaluates as truthy, so this usually works by accident. But 'false' does NOT evaluate as falsy — the string 'false' is truthy because it's a non-empty string. define( 'WP_DEBUG', 'false' ); actually ENABLES debug mode. I've seen this exact mistake cause a production site to suddenly start displaying PHP notices to visitors.

7. Editing the Wrong wp-config.php

If you have a multisite setup, a staging site in a subdirectory, or multiple WordPress installations on the same server, it's surprisingly easy to edit the wrong wp-config.php. I once spent 20 minutes debugging why my changes weren't taking effect before realizing I was editing the staging config while looking at the production site.

Always verify your working directory:

pwd
# Make sure you're in the right WordPress root

# Double-check by looking at the database name
grep DB_NAME wp-config.php
Enter fullscreen mode Exit fullscreen mode

Version Control and Environment-Specific Configs

If your WordPress site is in version control (and it should be), wp-config.php presents a problem. It contains database credentials, security keys, and environment-specific settings that shouldn't be committed to a repository.

The .gitignore Approach

The simplest approach: add wp-config.php to .gitignore and manage it manually on each environment.

# .gitignore
wp-config.php
Enter fullscreen mode Exit fullscreen mode

This works but means you have no version history for config changes, and you have to remember to create the file on new environments.

The Environment Variables Approach

A better approach is to read sensitive values from environment variables:

define( 'DB_NAME', getenv( 'WP_DB_NAME' ) );
define( 'DB_USER', getenv( 'WP_DB_USER' ) );
define( 'DB_PASSWORD', getenv( 'WP_DB_PASSWORD' ) );
define( 'DB_HOST', getenv( 'WP_DB_HOST' ) ?: 'localhost' );

define( 'WP_DEBUG', getenv( 'WP_DEBUG' ) === 'true' );
Enter fullscreen mode Exit fullscreen mode

Set the environment variables in your server config, .env file (loaded by a library like vlucas/phpdotenv), or Docker compose file. The wp-config.php itself becomes safe to commit because it contains no secrets.

The Local Config Approach

Another pattern I use frequently: keep a version-controlled wp-config.php that includes an environment-specific override file:

// At the top of wp-config.php, before any define() calls
if ( file_exists( __DIR__ . '/wp-config-local.php' ) ) {
    require_once __DIR__ . '/wp-config-local.php';
}
Enter fullscreen mode Exit fullscreen mode

Then in .gitignore:

wp-config-local.php
Enter fullscreen mode Exit fullscreen mode

Each developer creates their own wp-config-local.php with local database credentials and debug settings. The main wp-config.php checks if each constant is already defined before defining its defaults:

if ( ! defined( 'DB_NAME' ) ) {
    define( 'DB_NAME', 'production_db' );
}
if ( ! defined( 'WP_DEBUG' ) ) {
    define( 'WP_DEBUG', false );
}
Enter fullscreen mode Exit fullscreen mode

This gives you the best of both worlds: a version-controlled config with environment-specific overrides.

GUI Alternatives to Hand-Editing

If all of the above sounds like a lot of ways to accidentally break your site, that's because it is. There are tools that add a safety layer between you and the raw PHP file.

WP-CLI is the command-line alternative. Instead of opening the file in a text editor, you can read and write constants programmatically:

# Read a constant
wp config get WP_DEBUG

# Set a constant
wp config set WP_DEBUG true --raw

# Set a string constant
wp config set WP_SITEURL 'https://example.com'

# List all constants
wp config list
Enter fullscreen mode Exit fullscreen mode

The --raw flag tells WP-CLI to write the value as a raw PHP expression (so true becomes boolean true, not the string 'true'). Without --raw, WP-CLI wraps values in quotes. This matters for boolean and integer constants. For more WP-CLI techniques, see the WP-CLI commands every developer should know.

GUI plugins exist that let you manage wp-config.php from the WordPress admin. WP Multitool's Config Manager is one — it reads your current constants, lets you edit them from a form interface, validates syntax before writing, and creates a timestamped backup before every change. There are others, like WP Config File Editor and WPCode.

The advantage of any GUI approach is the same: you can't introduce a syntax error by mistyping a semicolon, and you always have a backup to restore if something goes wrong. The tradeoff is that you need a working WordPress installation to use them — if your site is already white-screened because of a bad config edit, the GUI can't help you. That's when you need SSH or FTP.

Recovery: When a Bad Edit Breaks Your Site

It happens. You edited wp-config.php, saved the file, and the site is showing a white screen or a PHP error. Here's the recovery process.

Step 1: Don't Panic, Get Access

You need file-level access to the server. This means SSH, SFTP, or your hosting provider's file manager. You cannot fix this from the WordPress admin because WordPress isn't loading.

ssh user@server
cd /var/www/html  # or wherever your WordPress root is
Enter fullscreen mode Exit fullscreen mode

Step 2: Look at the Error

If the white screen shows nothing, check the PHP error log:

# Common error log locations
tail -20 /var/log/php-fpm/error.log
tail -20 /var/log/apache2/error.log
tail -20 /var/log/nginx/error.log

# Or check PHP's configured error log
php -i | grep error_log
Enter fullscreen mode Exit fullscreen mode

The error message will tell you exactly what's wrong and which line number. Something like:

PHP Parse error: syntax error, unexpected end of file in /var/www/html/wp-config.php on line 47
Enter fullscreen mode Exit fullscreen mode

Step 3: Fix or Restore

If you know what you changed, fix the syntax error directly. If you're not sure what you changed or the file is a mess, restore from backup:

# If you had a backup
cp wp-config.php.bak wp-config.php

# If your caching plugin or config manager made a backup
ls wp-content/wp-config-backup*

# If you're using version control
git checkout wp-config.php
Enter fullscreen mode Exit fullscreen mode

If you have no backup at all, you can recreate wp-config.php from wp-config-sample.php:

cp wp-config-sample.php wp-config.php
Enter fullscreen mode Exit fullscreen mode

Then fill in your database credentials. If you don't remember them, check your hosting control panel, or look at the last known good backup in your hosting provider's system.

Step 4: Verify

# Quick syntax check without running the file
php -l wp-config.php
# Should output: No syntax errors detected

# Then load the site
curl -o /dev/null -s -w "HTTP: %{http_code}\n" https://yoursite.com
# Should output: HTTP: 200
Enter fullscreen mode Exit fullscreen mode

The php -l command is a linter — it checks for syntax errors without executing the file. Run this after every wp-config.php edit to catch problems before they go live. If you're editing remotely over SSH, make it a habit:

vim wp-config.php
# make your changes, save
php -l wp-config.php
# if clean, you're good. if error, fix it
Enter fullscreen mode Exit fullscreen mode

For a more detailed guide on diagnosing and recovering from site outages, see WordPress site down: what to do.

Terminal showing wp-config.php recovery workflow - find error fix it and verify with php lint

My Production wp-config.php Template

Here's the set of constants I add to every production WordPress site. Not all of them are necessary for every project, but this is my baseline:

/** Performance */
define( 'WP_MEMORY_LIMIT', '256M' );
define( 'WP_MAX_MEMORY_LIMIT', '512M' );
define( 'WP_POST_REVISIONS', 5 );
define( 'AUTOSAVE_INTERVAL', 120 );
define( 'EMPTY_TRASH_DAYS', 14 );
define( 'DISABLE_WP_CRON', true );

/** Security */
define( 'DISALLOW_FILE_EDIT', true );
define( 'FORCE_SSL_ADMIN', true );

/** Debugging (off for production) */
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_LOG', false );
define( 'WP_DEBUG_DISPLAY', false );
Enter fullscreen mode Exit fullscreen mode

And for staging/development:

/** Performance — relaxed for dev */
define( 'WP_MEMORY_LIMIT', '512M' );
define( 'WP_MAX_MEMORY_LIMIT', '512M' );
define( 'WP_POST_REVISIONS', 10 );
define( 'AUTOSAVE_INTERVAL', 60 );

/** Security — relaxed for dev */
define( 'DISALLOW_FILE_EDIT', false );

/** Debugging — full visibility */
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', true );
define( 'SCRIPT_DEBUG', true );
define( 'SAVEQUERIES', true );
Enter fullscreen mode Exit fullscreen mode

The difference between environments is just a handful of boolean flags and numbers. But those flags control whether your site exposes error details to visitors, allows file modifications from the admin, or stores unlimited post revisions until the database bloats.

The Real Problem with Hand-Editing wp-config.php

I started this article by calling wp-config.php the most dangerous file in WordPress. That's not because the constants are complex. They're actually trivial — key-value pairs, booleans, and integers.

The danger is the workflow. SSH into a production server, open a critical file in a text editor, type PHP code by hand, save, and hope for the best. No syntax validation. No automatic backup. No undo button.

For a file that controls database access, security policies, and debug behavior, that workflow belongs in 2006, not 2026.

Whether you use WP-CLI, a config management plugin, environment variables, or a deployment pipeline — anything that adds validation and backups between your intention and the raw file is an improvement. The specific tool matters less than having a safety net at all.

And if you do edit it by hand — because sometimes you need to, because the site is down and you're in SSH at midnight — run php -l wp-config.php before you close the terminal. It takes one second and it's the difference between going back to sleep and getting another phone call.

If your site is already sluggish and you're not sure whether it's a config issue or something deeper, the free scan checks your backend performance — autoload size, query health, PHP environment — in about 30 seconds.

Comparison of wp-config management approaches - hand editing vs WP-CLI vs GUI plugin

Top comments (0)