wp-config.php is the brain of a WordPress site: the database credentials, the salts, the debug flags. A default install leaves several defenses off. This checklist hardens wp-config.php against the most common attacks we see in logs every week.
1. Unique salt keys
Salts make stolen session cookies useless. They must be long random strings unique to your site.
// Generate fresh at: https://api.wordpress.org/secret-key/1.1/salt/
// Paste all eight over the placeholders
define('AUTH_KEY', 'long-random-string-1');
define('SECURE_AUTH_KEY', 'long-random-string-2');
define('LOGGED_IN_KEY', 'long-random-string-3');
define('NONCE_KEY', 'long-random-string-4');
define('AUTH_SALT', 'long-random-string-5');
define('SECURE_AUTH_SALT', 'long-random-string-6');
define('LOGGED_IN_SALT', 'long-random-string-7');
define('NONCE_SALT', 'long-random-string-8'); 2. Non-default table prefix
Default prefix is wp_. SQL injection payloads hardcode it. Change it once, before you have content.
$table_prefix = 'wp9x_'; // any short random prefix you like 3. Disable file editing in the admin
If an attacker steals an admin account, they can edit theme PHP files from wp-admin and drop a backdoor. Disable it.
define('DISALLOW_FILE_EDIT', true); 4. Force SSL for admin logins
define('FORCE_SSL_ADMIN', true); 5. Limit post revisions
WordPress keeps every revision forever, bloating the database.
define('WP_POST_REVISIONS', 5);
define('AUTOSAVE_INTERVAL', 300); 6. Disable plugin and theme installation from the dashboard
For production sites where plugin changes go through staging or Git, shut off runtime installs entirely.
define('DISALLOW_FILE_MODS', true); 7. Set WP_DEBUG explicitly
Never leave debug on in production. It leaks database errors and file paths to attackers. Set all three flags.
define('WP_DEBUG', false);
define('WP_DEBUG_DISPLAY', false);
define('WP_DEBUG_LOG', true); // still logs to wp-content/debug.log for you 8. Restrict wp-config.php permissions
# On Omega Digital shared hosting, set to 440 or 400
chmod 440 wp-config.php
# Verify
ls -la wp-config.php
# -r--r----- 1 cpuser nobody 3289 Apr 19 10:00 wp-config.php 9. Block direct access to wp-config.php via .htaccess
# Add to .htaccess at the site root
<Files wp-config.php>
Require all denied
</Files>
<Files xmlrpc.php>
Require all denied
</Files>
<Files .htaccess>
Require all denied
</Files> 10. Move wp-config.php up one directory
WordPress checks one level above the site root for wp-config.php. Moving it outside public_html means an Apache or PHP misconfiguration can never leak it via the browser.
# Assumes site is in /home/cpuser/public_html
mv /home/cpuser/public_html/wp-config.php /home/cpuser/wp-config.php
# Verify the site still loads — WordPress finds it automatically Bonus: limit login attempts
Not a wp-config change, but critical. Install Limit Login Attempts Reloaded or Wordfence's login throttle. Omega Digital also blocks IPs at the edge after 10 failed wp-login.php attempts within 60 seconds.
Verification
# Check permissions
stat -c '%a %n' wp-config.php
# Expected: 440 wp-config.php
# Confirm wp-config.php returns 403 from the browser
curl -I https://yourdomain.com/wp-config.php
# Expected: HTTP/2 403
# Confirm xmlrpc.php is blocked
curl -I https://yourdomain.com/xmlrpc.php
# Expected: HTTP/2 403 Common gotchas
- · Forgetting to update $table_prefix in the database when renaming it after content exists. Don't rename it on a live site without also running UPDATE queries across every wp_ table.
- · Setting DISALLOW_FILE_MODS on a site that autoupdates plugins. Core and plugin updates will fail. Only use on immutable deployments.
- · Wrong permissions. 444 works, 440 is better, 400 breaks some backup plugins. Test after changing.
- · Redirect loop after FORCE_SSL_ADMIN. Caused by reverse proxies not forwarding HTTPS. Add define('FORCE_SSL_ADMIN', true); $_SERVER['HTTPS'] = 'on';
Still stuck?
Email [email protected]; we can review your wp-config.php and flag anything we're surprised by.