Skip to content
All guides

wp-config.php Hardening and WordPress File Permissions

For developers 10 min readChecked October 26, 2026

The wp-config.php file holds your database password and the secret keys that sign your sessions. Careful wp-config.php hardening, together with correct file permissions and ownership, takes away several of the easiest ways an attacker can turn a small flaw into full control. This guide gives the settings, the numbers and the reasons.

Why wp-config.php hardening matters

This one file contains your database name, user and password, your authentication keys and salts, and settings that change how WordPress behaves. Anyone who can read it can read your database. Anyone who can write it can change how the whole site works.

Protecting it is mostly about three things: who can read the file on the server, whether the web server can ever serve it as text, and what the settings in it allow.

File permissions and ownership

As a starting point, set directories to 755 and files to 644, and make the sensitive file stricter. The file should be owned by the account that runs your site. Never make anything 777, which lets any process on the server change it.

On a typical shared host, 640 or 600 works for wp-config.php. On a server where the web server runs as a different user from the file owner, check the file is still readable by PHP before you tighten it. A value of 440 or 400 also stops accidental edits, but see the note on key rotation below.

Typical permission reset (adjust the path to your site root)
find /var/www/example.com -type d -exec chmod 755 {} \;
find /var/www/example.com -type f -exec chmod 644 {} \;
chmod 640 /var/www/example.com/wp-config.php

Useful security constants

These constants go above the line that says That's all, stop editing!. Add them one at a time and test.

  • DISALLOW_FILE_EDIT removes the theme and plugin code editors from the admin.
  • DISALLOW_FILE_MODS goes further: it also blocks installing and updating plugins, themes and core from the admin. Use it only if you deploy changes another way, and remember updates then become your responsibility.
  • FORCE_SSL_ADMIN forces https for sign-ins and the admin area.
  • WP_DEBUG should be false in production. If you need logs, set WP_DEBUG_LOG on and WP_DEBUG_DISPLAY off, so errors go to a file instead of the page.
wp-config.php
define( 'DISALLOW_FILE_EDIT', true );
define( 'FORCE_SSL_ADMIN', true );
define( 'WP_DEBUG', false );

// If you do need debug logs, keep errors off the page:
// define( 'WP_DEBUG', true );
// define( 'WP_DEBUG_LOG', true );
// define( 'WP_DEBUG_DISPLAY', false );

Keys and salts

WordPress uses eight keys and salts to sign the cookies that keep people signed in. Replacing them signs everyone out at once, including an attacker with a stolen cookie. You can generate fresh values from the official WordPress secret-key service.

Change them after any suspected break-in, after a developer or employee leaves, and on a regular schedule. One note: if you make wp-config.php read-only, anything that edits the file for you, such as an automatic key rotation, cannot write to it. Choose between a stricter file mode and automatic rotation, or change the keys by hand.

Move or block the file

WordPress also looks for wp-config.php one directory above the site root, so you can keep it outside the public web folder. This only works if the parent directory is not itself a WordPress install.

If you cannot move it, tell the web server to refuse any direct request for it. Normally PHP runs the file and shows nothing, but a server misconfiguration or a backup copy like wp-config.php.bak can expose the source.

Apache .htaccess in the site root
<Files wp-config.php>
  Require all denied
</Files>

# Backup and editor copies of config files
<FilesMatch "^(wp-config.*\.(bak|old|orig|save|swp|txt)|.*~)$">
  Require all denied
</FilesMatch>

# No directory listings
Options -Indexes

The same rules in nginx

nginx does not read .htaccess files, so the equivalent rules go in the server config. Reload nginx after editing.

nginx server block
location = /wp-config.php { deny all; }
location ~* /wp-config.*\.(bak|old|orig|save|swp|txt)$ { deny all; }

# No PHP execution in uploads
location ~* ^/wp-content/uploads/.*\.php$ { deny all; }

autoindex off;

Keep PHP out of uploads

The uploads folder is meant for images, documents and media. If an attacker slips a PHP file into it, running that file gives them control. Block PHP execution there so a planted script becomes a harmless download.

Apache: wp-content/uploads/.htaccess
<FilesMatch "\.(php|phtml|php[0-9])$">
  Require all denied
</FilesMatch>

Other files worth a look

A few more places deserve a quick check.

  • Delete readme.html and license.txt from the site root, or at least know they reveal your WordPress version. Updates put them back, so this is a small step.
  • Remove old backups, SQL dumps and zip files from the web folder. Search for *.sql, *.zip and *.bak.
  • Use SFTP or SSH, not plain FTP, which sends passwords in the clear.
  • Give each site its own hosting account or system user, so one infected site cannot read another's wp-config.php.

Wp-config.php hardening: questions

What permissions should wp-config.php have?

640 or 600 is a good choice on most servers. Use 440 or 400 if you also want to prevent accidental edits, but test that PHP can still read the file.

Is it safe to move wp-config.php above the web root?

Yes, WordPress supports it, as long as the parent folder is not another WordPress install. It keeps the file out of the public folder entirely.

Should I use DISALLOW_FILE_MODS?

Only if you deploy changes some other way and have a plan for updates. It also blocks updates from the dashboard, so it can leave a site out of date if you forget.

Does changing the database table prefix help?

Only a little. It does not stop a real attack, and changing it on a live site is easy to get wrong, so spend your time on updates, access control and backups first.

How do I get new keys and salts?

Use the official WordPress secret-key service to generate a set, replace the eight define lines in wp-config.php and expect everyone to be signed out.

Protect your WordPress site free

Most of this guide is one switch in Stack Guard.