wp-config.php Security Best Practices: 15 Essential Settings

On This Page

The wp-config.php file is the single most important file in your WordPress installation. It contains your database credentials, authentication keys, and security constants that control how WordPress behaves at its core.

Yet most WordPress administrators never touch it after the initial setup — leaving critical security features disabled by default.

In this guide, we’ll walk through 15 essential wp-config.php settings that significantly improve your site’s security posture. Each setting includes the exact code to add, an explanation of what it does, and the real-world attack it prevents.


Where Is wp-config.php and How to Edit It

The wp-config.php file is located in the root directory of your WordPress installation, typically at:

/var/www/html/wp-config.php
    — or —
~/public_html/wp-config.php

How to edit it:

  1. Connect to your server via SFTP (using FileZilla, Cyberduck, etc.) or SSH
  2. Download wp-config.php as a backup before making changes
  3. Edit the file with a plain text editor (not Microsoft Word)
  4. Upload the modified file back to the server

Important: Always back up wp-config.php before editing. A syntax error in this file will take your entire site offline.

All constants should be added above the line that says:

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

Part 1: Critical Security Settings

1. Disable Debug Mode in Production

What it does: When WP_DEBUG is enabled, WordPress displays PHP errors, warnings, and notices directly on your pages. This exposes internal file paths, function names, and database query details to anyone visiting your site.

The risk: Attackers use debug output to map your server’s directory structure, identify installed plugins, and find vulnerable code paths.

When you run a security scan with FunSentry, the scanner checks your homepage for visible PHP errors and warnings — a clear sign that debug mode is leaking information to the public.

// ✅ Production settings — disable all debug output
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_DISPLAY', false );
define( 'WP_DEBUG_LOG', false );

If you need to debug issues on a production site, log errors to a file instead of displaying them:

// ✅ Safe debugging — log to file, never display
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_DISPLAY', false );
define( 'WP_DEBUG_LOG', true ); // Logs to /wp-content/debug.log

Warning: If you enable WP_DEBUG_LOG, make sure /wp-content/debug.log is not publicly accessible. Block it via .htaccess or Nginx:

# Block access to debug.log
<Files debug.log>
  Order Allow,Deny
  Deny from all
</Files>

2. Disable File Editing from the Dashboard

What it does: WordPress includes a built-in code editor at Appearance → Theme File Editor and Plugins → Plugin File Editor that allows administrators to modify PHP files directly from the browser.

The risk: If an attacker gains admin access (through a stolen password, session hijacking, or a plugin vulnerability), they can inject malicious code into your theme or plugin files — creating backdoors, redirects, or data-stealing scripts — all without needing FTP access.

// ✅ Disable the built-in file editor
define( 'DISALLOW_FILE_EDIT', true );

For even stricter control, you can also prevent plugin and theme installations/updates from the dashboard:

// ✅ Prevent all file modifications from the dashboard
define( 'DISALLOW_FILE_MODS', true );

Note: With DISALLOW_FILE_MODS enabled, you’ll need to update plugins and themes via SFTP, WP-CLI, or a deployment pipeline. This is the recommended approach for production sites.


3. Force SSL for Admin and Logins

What it does: Forces all admin dashboard pages and login forms to use HTTPS encryption.

The risk: Without this setting, an administrator logging in over an unsecured network (e.g., coffee shop Wi-Fi) could have their credentials intercepted via a man-in-the-middle attack.

// ✅ Force HTTPS for admin and login pages
define( 'FORCE_SSL_ADMIN', true );
define( 'FORCE_SSL_LOGIN', true );

Prerequisite: Your site must have a valid SSL certificate installed. If you’re not sure, run a scan at FunSentry — the SSL/TLS module checks your certificate validity, expiration date, and HTTPS redirect behavior.


4. Set Authentication Keys and Salts

What it does: WordPress uses these eight cryptographic keys to encrypt information stored in user cookies. They make it significantly harder for attackers to forge or hijack user sessions.

The risk: Default or empty keys mean weaker cookie encryption. If an attacker obtains a session cookie, weak keys make it easier to decode or brute-force.

// ✅ Generate unique keys at: https://api.wordpress.org/secret-key/1.1/salt/
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' );

Generate fresh keys using the official WordPress API:

https://api.wordpress.org/secret-key/1.1/salt/

Visit that URL, copy the output, and paste it into your wp-config.php, replacing any existing keys.

Best practice: Rotate these keys periodically (every 6–12 months) or immediately after a suspected security breach. Changing the keys will force all currently logged-in users to re-authenticate.


5. Change the Database Table Prefix

What it does: By default, WordPress uses wp_ as the prefix for all database tables (e.g., wp_users, wp_options). Changing this makes SQL injection attacks harder, since attackers must guess the table names.

The risk: Automated SQL injection tools assume default table names. A custom prefix breaks these automated attacks.

// ✅ Use a custom table prefix (set during installation)
$table_prefix = 'fs29x_';

Important: This must be set before WordPress is installed. Changing it on an existing installation requires renaming all database tables and updating references in wp_options and wp_usermeta. Use a plugin like “Brozzme DB Prefix” if you need to change it post-installation.


Part 2: Access Control Settings

6. Block Direct Access to wp-config.php

The wp-config.php file itself must never be accessible via HTTP. FunSentry’s sensitive files scanner specifically checks if wp-config.php, wp-config.php.bak, wp-config.php~, and .wp-config.php.swp are publicly downloadable — and flags them as critical severity if found.

For Apache (.htaccess):

# Protect wp-config.php from direct access
<Files wp-config.php>
  Order Allow,Deny
  Deny from all
</Files>

For Nginx:

location = /wp-config.php {
    deny all;
    access_log off;
    log_not_found off;
}

Bonus: Move wp-config.php one directory above your WordPress root. WordPress automatically checks the parent directory:

/home/user/wp-config.php        ← WordPress finds it here
/home/user/public_html/          ← WordPress root (no wp-config.php here)
/home/user/public_html/wp-admin/
/home/user/public_html/wp-content/

This way, even if your web server is misconfigured, wp-config.php is outside the document root and cannot be served to browsers.


7. Disable User Registration (If Not Needed)

What it does: Controls whether new users can register accounts on your site.

The risk: Open registration allows attackers to create subscriber-level accounts, which can then be escalated through plugin vulnerabilities or used for spam.

Check this in the WordPress admin under Settings → General → Membership. If you don’t need public registration, uncheck it.

You can also enforce it in wp-config.php by ensuring the registration page is not accessible. FunSentry checks both the login page (/wp-login.php) and registration endpoint (/wp-login.php?action=register) and reports their status.


8. Limit Post Revisions

What it does: WordPress stores a complete copy of every saved revision for each post. On a busy site, this can lead to thousands of unnecessary database rows.

The risk: While not a direct security threat, a bloated database is slower to query and slower to back up. In a security incident, a lean database is faster to restore.

// ✅ Limit to 5 revisions per post
define( 'WP_POST_REVISIONS', 5 );

// Or disable revisions entirely
define( 'WP_POST_REVISIONS', false );

9. Configure Auto-Save Interval

What it does: WordPress auto-saves posts every 60 seconds by default. This can be extended to reduce database writes.

// ✅ Auto-save every 5 minutes (300 seconds)
define( 'AUTOSAVE_INTERVAL', 300 );

10. Disable WP-Cron (Use System Cron Instead)

What it does: WordPress has a built-in cron system (wp-cron.php) that triggers scheduled tasks (like publishing scheduled posts) on every page load. This is inefficient and creates a publicly accessible endpoint.

The risk: wp-cron.php can be abused to trigger resource-intensive tasks repeatedly, causing performance degradation. FunSentry checks if /wp-cron.php is publicly accessible and reports it.

// ✅ Disable WordPress's built-in cron
define( 'DISABLE_WP_CRON', true );

Then set up a real system cron job (runs every 15 minutes):

# Add to crontab (crontab -e)
*/15 * * * * wget -q -O - https://yoursite.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1

Or with WP-CLI:

*/15 * * * * cd /path/to/wordpress && wp cron event run --due-now > /dev/null 2>&1

Part 3: Database and Performance Security

11. Set Custom Database Connection Details

If your database is on a separate server, always use an explicit host rather than localhost:

// ✅ Explicit database connection
define( 'DB_HOST', '10.0.1.50:3306' );   // Internal IP, not public
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );

Security note: Never use root as the database user. Create a dedicated MySQL user with only the privileges WordPress needs:

-- Create a dedicated database user
CREATE USER 'wp_funsentry'@'10.0.1.%' IDENTIFIED BY 'strong_random_password_here';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX
  ON wordpress_db.* TO 'wp_funsentry'@'10.0.1.%';
FLUSH PRIVILEGES;

12. Increase Memory Limits

What it does: Sets the maximum memory PHP can use for WordPress operations. Low memory can cause white screens, failed updates, and incomplete backups.

// ✅ Standard memory limit
define( 'WP_MEMORY_LIMIT', '256M' );

// ✅ Admin tasks may need more (imports, updates)
define( 'WP_MAX_MEMORY_LIMIT', '512M' );

13. Define the Trash Auto-Empty Interval

What it does: WordPress keeps deleted posts and pages in the trash. By default, trash is emptied after 30 days.

// ✅ Empty trash after 7 days
define( 'EMPTY_TRASH_DAYS', 7 );

// Disable trash entirely (items are permanently deleted)
define( 'EMPTY_TRASH_DAYS', 0 );

Warning: Setting this to 0 means clicking “Delete” is permanent — there’s no undo. This is appropriate for high-security environments where you don’t want recoverable data lingering.


Part 4: Advanced Hardening

14. Block External HTTP Requests (Selective)

What it does: Prevents WordPress from making outbound HTTP requests to external servers. This blocks phone-home features, auto-updates, and external API calls.

// Block ALL external requests (strict mode)
define( 'WP_HTTP_BLOCK_EXTERNAL', true );

// Allow specific hosts (comma-separated)
define( 'WP_ACCESSIBLE_HOSTS', 'api.wordpress.org,downloads.wordpress.org,*.github.com' );

Use case: If your site has been compromised, malware often phones home to a command-and-control server. Blocking external requests contains the damage while you clean the infection.

Warning: This breaks auto-updates and plugin/theme installation. Only use on sites with a manual deployment workflow.


15. Define a Custom Content Directory

What it does: Moves the wp-content directory to a custom location with a non-standard name, making it harder for attackers to target.

// ✅ Move wp-content to a custom directory
define( 'WP_CONTENT_DIR', dirname(__FILE__) . '/assets' );
define( 'WP_CONTENT_URL', 'https://yoursite.com/assets' );

Attackers commonly probe /wp-content/plugins/ and /wp-content/uploads/ for known vulnerabilities and directory listings. Renaming the directory breaks these automated scans.

Note: Some poorly coded plugins may break if they hardcode /wp-content/ paths. Test thoroughly after making this change.


The Complete Secure wp-config.php Template

Here’s a consolidated template with all the security settings covered in this guide:

<?php
/**
 * WordPress Security-Hardened Configuration
 * Generated with guidance from FunSentry (https://www.funsentry.com)
 */

// ── Database Settings ──
define( 'DB_NAME',     'your_database_name' );
define( 'DB_USER',     'your_database_user' );    // Never use 'root'
define( 'DB_PASSWORD', 'your_strong_password' );
define( 'DB_HOST',     'localhost' );
define( 'DB_CHARSET',  'utf8mb4' );
define( 'DB_COLLATE',  '' );

// ── Custom Table Prefix ──
$table_prefix = 'fs29x_';    // Change from default 'wp_'

// ── Authentication Keys and Salts ──
// Generate at: https://api.wordpress.org/secret-key/1.1/salt/
define( 'AUTH_KEY',         'generate-unique-key-here' );
define( 'SECURE_AUTH_KEY',  'generate-unique-key-here' );
define( 'LOGGED_IN_KEY',    'generate-unique-key-here' );
define( 'NONCE_KEY',        'generate-unique-key-here' );
define( 'AUTH_SALT',        'generate-unique-key-here' );
define( 'SECURE_AUTH_SALT', 'generate-unique-key-here' );
define( 'LOGGED_IN_SALT',   'generate-unique-key-here' );
define( 'NONCE_SALT',       'generate-unique-key-here' );

// ── Security Hardening ──
define( 'WP_DEBUG',              false );            // No debug in production
define( 'WP_DEBUG_DISPLAY',      false );            // Never display errors
define( 'WP_DEBUG_LOG',          false );            // No debug log file
define( 'DISALLOW_FILE_EDIT',    true );             // Disable theme/plugin editor
define( 'DISALLOW_FILE_MODS',    true );             // Disable all file modifications
define( 'FORCE_SSL_ADMIN',       true );             // Force HTTPS for admin
define( 'FORCE_SSL_LOGIN',       true );             // Force HTTPS for login

// ── Performance & Maintenance ──
define( 'WP_POST_REVISIONS',     5 );                // Limit revisions
define( 'AUTOSAVE_INTERVAL',     300 );              // Auto-save every 5 min
define( 'EMPTY_TRASH_DAYS',      7 );                // Empty trash after 7 days
define( 'DISABLE_WP_CRON',       true );             // Use system cron instead
define( 'WP_MEMORY_LIMIT',      '256M' );            // PHP memory limit
define( 'WP_MAX_MEMORY_LIMIT',  '512M' );            // Admin memory limit

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

How to Verify Your Settings Are Working

After applying these changes, verify that your configuration is effective:

1. Run a FunSentry Scan

Visit www.funsentry.com and scan your site. The scanner checks for:

  • Debug output leaks — Detects PHP errors, warnings, and notices on your homepage
  • Sensitive file exposure — Checks if wp-config.php, .env, debug.log, and backup files are publicly accessible
  • User enumeration — Tests if /?author=1 reveals usernames
  • Login page exposure — Reports if /wp-login.php is accessible
  • Registration page status — Checks if open registration is enabled
  • WP-Cron exposure — Verifies if /wp-cron.php is publicly reachable

2. Manual Verification

# Test debug mode (should NOT show PHP errors)
curl -s https://yoursite.com | grep -i "fatal error\|warning\|notice\|deprecated"

# Test wp-config.php protection (should return 403)
curl -I https://yoursite.com/wp-config.php

# Test wp-config backup files (should return 403 or 404)
curl -I https://yoursite.com/wp-config.php.bak
curl -I https://yoursite.com/wp-config.php~

# Test debug.log protection (should return 403 or 404)
curl -I https://yoursite.com/wp-content/debug.log

# Test user enumeration (should NOT redirect to /author/username/)
curl -I https://yoursite.com/?author=1

Common Mistakes to Avoid

MistakeWhy It’s DangerousFix
Leaving WP_DEBUG as true in productionExposes file paths and internal errorsSet to false
Using root as the DB userA compromised site gives full database server accessCreate a dedicated user with minimal privileges
Default wp_ table prefixAutomated SQL injection tools target default namesUse a random prefix
Never rotating auth keysCompromised keys remain valid indefinitelyRegenerate every 6–12 months
debug.log publicly accessibleContains SQL queries, file paths, plugin errorsBlock via .htaccess or delete after debugging
Storing wp-config.php backups in webrootFiles like wp-config.php.bak are downloadableNever store backups in the document root
Leaving the theme/plugin editor enabledAn admin account compromise becomes a full code execution compromiseSet DISALLOW_FILE_EDIT to true

Summary

SettingConstantRecommended Value
Debug modeWP_DEBUGfalse
Debug displayWP_DEBUG_DISPLAYfalse
File editorDISALLOW_FILE_EDITtrue
File modificationsDISALLOW_FILE_MODStrue
SSL adminFORCE_SSL_ADMINtrue
Table prefix$table_prefixCustom (not wp_)
Post revisionsWP_POST_REVISIONS5
WP-CronDISABLE_WP_CRONtrue
Auth keysAll 8 keys/saltsUnique random values
Memory limitWP_MEMORY_LIMIT256M

The wp-config.php file is your first line of defense. These 15 settings take about 10 minutes to implement and immediately close some of the most commonly exploited misconfigurations in WordPress.

Don’t guess whether your settings are working — verify them. Run a free scan at FunSentry to check your debug output, sensitive file exposure, user enumeration, and more.


This article was written by the FunSentry security research team. FunSentry is a free online WordPress security scanner that performs passive checks on debug mode, sensitive file exposure, user enumeration, login page access, and other wp-config.php-related security issues. Scan your site now to verify your configuration.