Cart
Net 9 regions SYD 264 ms FRA 18 ms NRT 232 ms Uptime 30d 99.997 %

04 / WordPress

Hardening wp-config.php: the security checklist

Ten wp-config.php changes that block the most common WordPress attacks, with the exact lines to add.

8 min read · Updated April 2026

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.

php
// 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.

php
$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.

php
define('DISALLOW_FILE_EDIT', true);

4. Force SSL for admin logins

php
define('FORCE_SSL_ADMIN', true);

5. Limit post revisions

WordPress keeps every revision forever, bloating the database.

php
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.

php
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.

php
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

bash
# 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

apache
# 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.

bash
# 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

bash
# 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.

Support

Email [email protected] with your account email and the exact error. Direct support.