Essential wp-config.php Tweaks Every WordPress Site Should Have

The wp-config.php constants every agency should know - security hardening, performance settings, debug tools, and database configuration explained.

Dobromir Dechev
Dobromir WordPress agency owner

Quick answer

wp-config.php controls security, performance, database and debugging behaviour before WordPress fully loads. The highest-value entries are disabling the file editor, limiting post revisions, setting a real memory limit, and keeping debug output out of production.

wp-config.php is the most important file in any WordPress installation. It controls database connections, security keys, debug settings, memory limits, and dozens of behaviours that cannot be changed through the admin interface. Most developers set it up once and never look at it again - leaving performance and security improvements on the table.

This guide covers every wp-config.php constant worth knowing, grouped by category, with explanations of when and why to use each one.

Security hardening

Authentication keys and salts

Your WordPress install came with a set of authentication keys and salts. These are used to encrypt cookies and password hashes. If you migrated a site from somewhere else, regenerate them immediately:

Visit https://api.wordpress.org/secret-key/1.1/salt/ to generate a fresh set. Replace the existing block in wp-config.php:

define( 'AUTH_KEY',         'unique value here' );
define( 'SECURE_AUTH_KEY',  'unique value here' );
define( 'LOGGED_IN_KEY',    'unique value here' );
define( 'NONCE_KEY',        'unique value here' );
define( 'AUTH_SALT',        'unique value here' );
define( 'SECURE_AUTH_SALT', 'unique value here' );
define( 'LOGGED_IN_SALT',   'unique value here' );
define( 'NONCE_SALT',       'unique value here' );

Regenerating these logs out all existing sessions. Tell clients before doing it on a live site.

Disable file editing from the admin

The built-in theme and plugin editor is a direct PHP code execution interface for anyone who gets admin access. Disable it:

define( 'DISALLOW_FILE_EDIT', true );

Disable plugin/theme installation from the admin

For maximum-hardened client sites where you control deployments:

define( 'DISALLOW_FILE_MODS', true );

This prevents all file modifications from the admin, including updates. Only use this if you have a CI/CD process for updates, or if the site is completely static and never needs changes.

Force HTTPS for admin and login

define( 'FORCE_SSL_ADMIN', true );

Limit login attempts

wp-config.php cannot block brute force directly, but combined with a server-level fail2ban rule, you can lock out IPs after repeated failures. Add custom login error messages:

// Not a wp-config.php constant, but related: place in functions.php
add_filter( 'login_errors', fn() => 'Incorrect credentials.' );

If you are running a multisite or have cookies behaving unexpectedly after SSL migration:

define( 'COOKIE_DOMAIN', 'yourdomain.com' );

Performance settings

WordPress memory limit

define( 'WP_MEMORY_LIMIT',     '256M' ); // frontend
define( 'WP_MAX_MEMORY_LIMIT', '512M' ); // admin operations

Limit post revisions

define( 'WP_POST_REVISIONS', 5 ); // keep 5 revisions, delete the rest
// Or disable entirely:
define( 'WP_POST_REVISIONS', false );

On a site with 5,000 posts and unlimited revisions, the wp_posts table can grow to hundreds of thousands of rows. Most are never used. 5 revisions is enough for a safety net.

Autosave interval

WordPress autosaves the editor every 60 seconds. This generates database writes and revision records. For busy editorial teams who frequently have the editor open:

define( 'AUTOSAVE_INTERVAL', 300 ); // every 5 minutes instead of 1

Empty trash automatically

By default WordPress keeps trashed posts for 30 days. For sites with high content turnover:

define( 'EMPTY_TRASH_DAYS', 7 ); // auto-delete after 7 days
// Or disable trash entirely:
define( 'EMPTY_TRASH_DAYS', 0 ); // immediately deleted, no undo

Disable WP Cron and use server cron

define( 'DISABLE_WP_CRON', true );

Add a proper server cron job:

*/5 * * * * cd /var/www/html && wp cron event run --due-now --quiet

This is important for sites with accurate scheduled publishing, email queues, or backup plugins that run on a schedule.

Enable object cache persistence

If you are using a Redis or Memcached object cache (via a drop-in or plugin), WordPress needs to know the cache should persist between requests. This is usually handled by the cache plugin, but occasionally needs a manual constant:

define( 'WP_CACHE', true );

Database configuration

Table prefix

Set during install, but worth documenting: the default wp_ prefix makes SQL injection attacks slightly easier because attackers know your table names. Change it during migration:

$table_prefix = 'site42_'; // custom prefix

Changing this on an existing install requires updating all table names and the prefix values in wp_options and wp_usermeta - use a plugin like Brozzme DB Prefix Change.

Database charset and collation

WordPress defaults to utf8mb4 which supports full Unicode including emoji. Only change this if you have a specific legacy reason:

define( 'DB_CHARSET',   'utf8mb4' );
define( 'DB_COLLATE',   'utf8mb4_unicode_ci' );

Database host with custom port

If your database server runs on a non-standard port:

define( 'DB_HOST', 'localhost:3307' );

Or with a Unix socket (faster than TCP on the same server):

define( 'DB_HOST', 'localhost:/var/run/mysqld/mysqld.sock' );

Debugging and development

Full debug mode

Never leave this on in production. Use it locally or on staging:

define( 'WP_DEBUG',         true );  // enable error display
define( 'WP_DEBUG_LOG',     true );  // write errors to /wp-content/debug.log
define( 'WP_DEBUG_DISPLAY', false ); // do not show errors publicly

Script debug mode

Forces WordPress to load unminified versions of scripts and styles. Useful when debugging a JS conflict in the admin:

define( 'SCRIPT_DEBUG', true );

Concatenate scripts (admin only)

WordPress concatenates admin scripts into a single request by default. If you are diagnosing a JavaScript conflict in the admin:

define( 'CONCATENATE_SCRIPTS', false );

Logging slow cron jobs

If you suspect a cron job is causing problems:

define( 'SAVEQUERIES', true ); // logs all DB queries - very verbose, remove after use

Multisite configuration

Enable multisite

define( 'WP_ALLOW_MULTISITE', true );

After enabling and running through the Network Setup screen, WordPress adds additional constants automatically:

define( 'MULTISITE',            true );
define( 'SUBDOMAIN_INSTALL',    false ); // false = subdirectory, true = subdomain
define( 'DOMAIN_CURRENT_SITE',  'yourdomain.com' );
define( 'PATH_CURRENT_SITE',    '/' );
define( 'SITE_ID_CURRENT_SITE', 1 );
define( 'BLOG_ID_CURRENT_SITE', 1 );

File system and uploads

Upload path

Change the default uploads directory:

define( 'UPLOADS', 'media' ); // instead of /wp-content/uploads/

FTP credentials for updates (rare)

If WordPress cannot write directly to the filesystem (unusual on modern setups), it falls back to FTP for updates:

define( 'FTP_HOST',     'ftp.yourdomain.com' );
define( 'FTP_USER',     'username' );
define( 'FTP_PASS',     'password' );
define( 'FS_METHOD',    'direct' ); // or 'ftpext', 'ftpsockets', 'ssh2'

Setting FS_METHOD to direct tells WordPress to write files directly without FTP, which is correct for most VPS and managed hosting setups where the web server user owns the files.

HTTPS and proxy settings

Site URL and home URL

Override the database values entirely:

define( 'WP_HOME',    'https://yourdomain.com' );
define( 'WP_SITEURL', 'https://yourdomain.com' );

Useful when migrating, or when the database has the wrong URL locked in after a failed migration.

Reverse proxy HTTPS detection

if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] )
     && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
    $_SERVER['HTTPS'] = 'on';
}

For installs in subdirectories:

define( 'COOKIEPATH',     '/' );
define( 'SITECOOKIEPATH', '/' );

A clean wp-config.php template

Here is a minimal, well-structured wp-config.php template that includes all the above:

<?php

// === Database ===
define( 'DB_NAME',     getenv( 'DB_NAME' )     ?: 'database_name' );
define( 'DB_USER',     getenv( 'DB_USER' )     ?: 'database_user' );
define( 'DB_PASSWORD', getenv( 'DB_PASSWORD' ) ?: 'database_password' );
define( 'DB_HOST',     getenv( 'DB_HOST' )     ?: 'localhost' );
define( 'DB_CHARSET',  'utf8mb4' );
define( 'DB_COLLATE',  'utf8mb4_unicode_ci' );

// === Keys & Salts ===
// Generate from: https://api.wordpress.org/secret-key/1.1/salt/
define( 'AUTH_KEY',         '...' );
define( 'SECURE_AUTH_KEY',  '...' );
define( 'LOGGED_IN_KEY',    '...' );
define( 'NONCE_KEY',        '...' );
define( 'AUTH_SALT',        '...' );
define( 'SECURE_AUTH_SALT', '...' );
define( 'LOGGED_IN_SALT',   '...' );
define( 'NONCE_SALT',       '...' );

// === Performance ===
define( 'WP_MEMORY_LIMIT',     '256M' );
define( 'WP_MAX_MEMORY_LIMIT', '512M' );
define( 'WP_POST_REVISIONS',   5 );
define( 'AUTOSAVE_INTERVAL',   300 );
define( 'EMPTY_TRASH_DAYS',    7 );
define( 'DISABLE_WP_CRON',     true );
define( 'WP_CACHE',            true );

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

// === Debug (production: all false) ===
define( 'WP_DEBUG',         false );
define( 'WP_DEBUG_LOG',     false );
define( 'WP_DEBUG_DISPLAY', false );
define( 'SCRIPT_DEBUG',     false );

// === URLs ===
define( 'WP_HOME',    'https://yourdomain.com' );
define( 'WP_SITEURL', 'https://yourdomain.com' );

// === Reverse proxy HTTPS ===
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] )
     && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
    $_SERVER['HTTPS'] = 'on';
}

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

/* Stop editing. */
if ( ! defined( 'ABSPATH' ) ) {
    define( 'ABSPATH', __DIR__ . '/' );
}
require_once ABSPATH . 'wp-settings.php';

Using environment variables for credentials

Hardcoding database credentials in wp-config.php works, but committing that file to git is a common security mistake. Use environment variables instead:

define( 'DB_NAME',     getenv( 'DB_NAME' ) );
define( 'DB_USER',     getenv( 'DB_USER' ) );
define( 'DB_PASSWORD', getenv( 'DB_PASSWORD' ) );

Set the environment variables in your server config (Apache SetEnv, Nginx fastcgi_param, or a .env file loaded by a package like vlucas/phpdotenv). This way wp-config.php can safely be committed to version control without exposing credentials.

Managed hosts like Kinsta and Cloudways already inject database credentials as environment variables and provide a wp-config.php that reads from them.


Frequently Asked Questions

What are the most important wp-config.php settings?
Disabling the built-in file editor with `DISALLOW_FILE_EDIT`, limiting revisions with `WP_POST_REVISIONS`, setting `WP_MEMORY_LIMIT` appropriately, and ensuring `WP_DEBUG` is off in production. These four address the most common security, database-bloat and stability problems on a typical site.
Should I disable the WordPress file editor?
Yes on any production site. `define('DISALLOW_FILE_EDIT', true);` removes the ability to edit theme and plugin PHP from the admin, which turns a compromised admin account from a full server foothold into a much smaller problem. There is no real downside — legitimate edits belong in version control.
How do I limit WordPress post revisions?
Set `define('WP_POST_REVISIONS', 5);` in wp-config.php to keep the five most recent revisions per post, or `false` to disable them entirely. Unlimited revisions are a leading cause of database bloat on content-heavy sites, since every autosave adds a row.
Is it safe to enable WP_DEBUG on a live site?
Only with logging rather than display. `WP_DEBUG` combined with `WP_DEBUG_DISPLAY` set to false and `WP_DEBUG_LOG` set to true writes errors to a file instead of showing them to visitors. Never display errors publicly — they leak paths and versions. Also watch the log size, since a large debug log slows every request.
Where should new constants go in wp-config.php?
Above the `/* That's all, stop editing! */` line. Anything added below it is defined after WordPress has already bootstrapped, so it will be ignored — which is the usual reason a correct-looking constant appears to have no effect.

Was this article helpful?