---
title: wp-config.php Security Settings Every Site Should Use
description: "The wp-config.php security settings that matter: lock the file editor, rotate keys, hide debug logs, and block the backup copies that leak your database."
url: "https://skybootstrap.com/wp-config-php-security/"
canonical_url: "https://skybootstrap.com/wp-config-php-security/"
date: "2026-10-26T05:37:00+06:00"
modified: "2026-10-25T18:38:47+06:00"
author: Skybootstrap Team
type: article
site: SkyBootstrap
language: en-US
---

# wp-config.php Security Settings Every Site Should Use

The `wp-config.php` file holds your database password and secret keys, and a few lines in it can turn off the admin file editor, rotate every session, and keep debug logs out of public view. On our test site, setting `DISALLOW_FILE_EDIT` removed the plugin and theme editors and returned a 403 to anyone who requested them directly. This guide covers the settings worth adding, every one verified on a WordPress 7.1.3 install, plus the file-copy mistake that leaks the whole file as plain text.

## Lock the admin file editor

Add `define( 'DISALLOW_FILE_EDIT', true );` to stop anyone, including an attacker who gets into wp-admin, from editing plugin and theme code through the dashboard. The built-in editor lets an administrator rewrite PHP files from the browser, which is exactly what an attacker wants after stealing an admin session.

On our test site, before the constant an admin could open `plugin-editor.php` (HTTP 200). After adding it and clearing the PHP cache, the same page returned 403 and the editor links disappeared from the admin menu (test T1b). Checking the capabilities directly, the admin lost `edit_plugins` and `edit_themes` but kept `install_plugins` and `update_core`, so updates still work; only the code editor is gone.

A caveat we hit: PHP’s opcache served the old config for a moment, so the change looked like it hadn’t taken until the cache refreshed. On a live site this clears on its own quickly; if you’re testing, reload PHP to see it.

## Turn off all file modifications (stronger, with a trade-off)

For a site where plugins and themes are managed outside the dashboard, `define( 'DISALLOW_FILE_MODS', true );` blocks every file change from the admin, not just code editing. It’s stronger than `DISALLOW_FILE_EDIT`, but it has a cost worth knowing.

On our test site, with this constant on, the admin lost `install_plugins`, `update_plugins`, `delete_plugins`, `install_themes`, `update_core`, and `update_languages`; `plugin-install.php` returned 403 (test T2). The install and update screens simply vanish.

The trade-off: it also stops automatic background updates, security releases included. In the WordPress 7.1.3 source, the automatic updater is disabled whenever file modifications aren’t allowed (`WP_Automatic_Updater::is_disabled()` checks `wp_is_file_mod_allowed()`, which returns false when `DISALLOW_FILE_MODS` is set). So use this only where something else keeps the site updated, such as deployment from version control or a managed host. On an ordinary site it does more harm than good, because it silently turns off the security updates that matter most.

## Rotate your secret keys to force everyone out

The salts and secret keys in `wp-config.php` sign the cookies that keep users logged in, and changing them logs every user out at once. That’s your emergency “log everyone out” button after a compromise or a shared-password scare.

On our test site, an admin with a valid session cookie got the dashboard (HTTP 200). We ran `wp config shuffle-salts`, which replaces the eight keys, and after the cache cleared the same cookie was bounced to the login page with `reauth=1` (test T3). Every existing session, including an attacker’s, is invalidated; everyone signs in again.

If you don’t have WP-CLI, generate a fresh set from the official secret-key service and paste them over the eight `define()` lines for `AUTH_KEY` through `NONCE_SALT`. Any install that still has the sample `'put your unique phrase here'` placeholders is effectively unsigned; replace them immediately.

## Keep debug logging out of public view

If you turn on debug logging, send the log somewhere the public can’t read it, because the default location is web-accessible and logs leak paths and sometimes secrets. Developers enable `WP_DEBUG_LOG` to capture errors, and by default WordPress writes them to `wp-content/debug.log`.

We reproduced the exposure (test T4). With `WP_DEBUG`, `WP_DEBUG_LOG` true, and `WP_DEBUG_DISPLAY` false, a test warning was written to `wp-content/debug.log`, and a plain browser request to `https://sec.test/wp-content/debug.log` returned it with HTTP 200, file path and all. Anyone who guesses that URL reads your errors.

Two fixes. Keep display off in production, which the settings above already do, so errors never show on the page:

```
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', '/var/log/wordpress/debug.log' ); // a path outside the web root
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );
```

Pointing `WP_DEBUG_LOG` at a path outside the web root is the real fix. On our test, after moving the log out of the site folder and deleting the old one, the public URL `wp-content/debug.log` returned a 301 (nothing there to serve) while logging still worked to the new location (test T5). On a live site, turn debug logging off entirely once you’re done; leave it on only while actively debugging.

## Don’t leave readable copies of wp-config.php

Never leave a backup or editor copy of `wp-config.php` in the site folder, because the server runs `.php` but serves anything else as text, so `wp-config.php.bak` hands out your database credentials. The live file is safe: the server executes it and the browser gets nothing. A copy with any other extension is not.

We tested the common editor and backup names (test T6). The real `wp-config.php` returned 200 with `DB_NAME` not visible (it ran as code). But `wp-config.php.bak`, `wp-config.php~`, `wp-config.old`, and `wp-config.php.save` each returned 200 with `DB_NAME` in plain text. An attacker trying those names reads your entire configuration: database host, user, password, and secret keys.

The fix is to not create such files, and to block them at the server as a backstop. One rule covers every copy except the real file:

```
# nginx: refuse any wp-config.* that isn't wp-config.php
location ~* /wp-config\.(?!php$) { deny all; }
```

```
# Apache .htaccess: same idea
<FilesMatch "^wp-config\.(?!php$)">
Require all denied
</FilesMatch>
```

With one rule each, the real file still loaded (200) while every copy returned 403 on both servers (test T6c).

## Moving wp-config.php above the web root

WordPress will read `wp-config.php` from one directory above your site folder, which puts it outside the web root entirely, where no misconfiguration can ever serve it. It’s an optional extra step, with one condition.

The condition: WordPress uses the parent-directory copy only when there’s no `wp-config.php` in the site folder and the parent directory holds a `wp-config.php` but no `wp-settings.php` (`wp-load.php` checks for exactly that, so the parent folder must not itself be another WordPress root). On our first test the move failed with a 503 because the lab’s config used a relative path for its database; once we made that path absolute, moving the file to the parent directory worked, the site returned 200, and requesting `wp-config.php` in the web root returned 404 because it was no longer there (test T7b).

This is worth doing on a single-site server you control. On shared hosting where the parent directory is shared or inaccessible, skip it; the file-copy rule above already closes the realistic leak.

## Frequently Asked Questions

### What does DISALLOW_FILE_EDIT do in wp-config.php?

DISALLOW_FILE_EDIT removes the dashboard’s plugin and theme code editor, the tool an attacker uses to rewrite your PHP after stealing an admin session. On our test site, adding define( ‘DISALLOW_FILE_EDIT’, true ); returned a 403 for the editor and took it off the menu, while plugin installs and updates still worked. It’s safe on every site and one of the highest-value single lines you can add.

### Does DISALLOW_FILE_MODS stop WordPress updates?

Yes, including automatic security updates, so use it carefully. It blocks every file change from the admin: installing and updating plugins and themes, and core updates. In the WordPress source, the automatic updater is disabled whenever file modifications aren’t allowed. Only set it where updates are handled another way, such as deployment from version control or a managed host; on an ordinary site it does more harm than good.

### Where should WordPress debug logs be stored?

Outside the web root, never the default wp-content/debug.log. On our test site that default file was downloadable at its public URL, exposing paths and errors to anyone. Point WP_DEBUG_LOG at a path outside the site folder and keep WP_DEBUG_DISPLAY false in production, so errors are logged privately and never shown on the page. Turn debug logging off entirely once you’ve finished debugging.

### Can someone read my wp-config.php file?

Not the live file: the server runs it as PHP and the browser gets nothing. But a copy with another extension is served as plain text, so a wp-config.php.bak or wp-config.old hands over your database password and secret keys. We confirmed this on the test site. Don’t leave such copies in the site folder, and add one server rule denying any wp-config file that isn’t wp-config.php.

## The short list of wp-config.php settings

If you add nothing else to wp-config.php, add these:

1. `DISALLOW_FILE_EDIT`: removes the dashboard code editor. Safe on every site.
2. Fresh secret keys: replace any placeholder salts, and rotate them to force a global logout after trouble.
3. Debug display off in production, and if you log, log outside the web root.
4. No `.bak`, `.old`, or `~` copies of `wp-config.php` in the site folder, plus the one server rule as a backstop.

Add `DISALLOW_FILE_MODS` only where updates are handled elsewhere, and move the file above the web root if you control the server. These settings protect the file that protects everything else; file permissions on that same file are the next layer, covered in [WordPress file permissions](https://skybootstrap.com/wordpress-file-permissions/). For the full pass, see [the full WordPress security checklist](https://skybootstrap.com/wordpress-security-checklist/).