A stray line in an .htaccess file or a single missing chmod can turn wp-config.php from the most protected file on a WordPress install into the easiest way to walk off with database credentials, secret keys, and salts. Securing wp-config.php – Permissions and Placement is really about two separate but related questions: where the file physically lives on the server, and who or what is allowed to read it once it’s there. Get both wrong and an attacker doesn’t need SQL injection or XSS to own the site — they just need the file served as plain text.
Why wp-config.php Is the Single Highest-Value Target on a WordPress Install
Everything else on a WordPress site is downstream of this one file. It holds the database name, username, password, host, the eight secret authentication keys and salts, and often the table prefix. Anyone who can read it can connect directly to the database, dump the wp_users table, and forge valid session cookies using the AUTH_KEY and LOGGED_IN_KEY values without ever touching wp-login.php.
The common misconception is that HTTPS and a strong admin password are enough. They aren’t, because the risk here isn’t credential theft over the wire — it’s the web server misconfigured to serve PHP as static text, or a backup/editor tool leaving a copy like wp-config.php.bak or wp-config.php~ sitting in the web root. Apache with an old mod_php setup, a misconfigured Nginx location block, or a text editor’s autosave feature has exposed this file on production servers more times than any injection attack has.
Permissions: What the Numbers Actually Mean
On a standard Linux/Apache or Nginx stack, wp-config.php should be owned by the user the PHP process runs as (often www-data, but on shared hosting frequently a dedicated account per site) and set to 640 or even 600. 644 — the default many hosts leave in place — means any local user on a shared server can read it. On shared hosting with hundreds of tenants under a single Apache instance without proper user isolation (no suexec, no PHP-FPM pools per user), 644 is effectively “world-readable” in practice.
A few concrete numbers worth knowing:
– 600 (owner read/write only) is ideal when PHP-FPM runs as a dedicated pool user matching the file owner.
– 640 (owner read/write, group read) is the common compromise when the web server group needs read access but no execute.
– 644 or looser should never appear on this file — audit it the same day you find it.
The mistake practitioners make here is setting permissions once during initial server setup and never checking again. A migration script, a “fix permissions” cron job someone wrote in 2019, or a careless `chmod -R 755` run against the whole wp-content directory during a plugin install can silently reset wp-config.php back to something readable. A seasoned WordPress administrator checks file permissions as part of a recurring audit, not a one-time hardening step, precisely because these regressions happen quietly.
Placement: Moving the File Above the Web Root
WordPress core has supported this since roughly 4.4: if wp-config.php isn’t found in the site’s root directory, WP_CONFIG_PATH lookup logic in wp-load.php automatically checks one directory up. That means on a typical structure like /var/www/example.com/public_html/, moving wp-config.php to /var/www/example.com/ (one level above public_html) keeps it completely outside the document root that Nginx or Apache actually serves.
The practical benefit: even a catastrophic misconfiguration — Nginx serving .php files as text/plain because of a broken fastcgi_pass block, for instance — can’t expose a file the web server was never configured to reach in the first place. This single change removes an entire class of accidental-disclosure incidents.
Steps to do it safely:
1. Confirm the parent directory is genuinely outside the document root — check the actual DocumentRoot or root directive in the vhost config, not just assume it.
2. Copy (don’t move yet) wp-config.php up one level.
3. Test the site loads correctly with the copy in place.
4. Once confirmed, delete the original from the web root.
5. Re-check permissions on the new location — moving it doesn’t fix loose permissions, it just changes the path.
This doesn’t help on every setup. Some managed hosts (certain configurations on WP Engine or Pantheon, for example) use containerized or read-only filesystem layouts where the concept of “one directory up” doesn’t map cleanly, and moving the file can break deploys or staging syncs. Multisite installs and some Docker-based WordPress images also assume a fixed relative path. Always test in staging first.
Common Mistakes Practitioners Actually Make
The recurring pattern is treating wp-config.php security as a launch-day checklist item rather than something that needs re-verification. Three patterns show up again and again: leaving editor backup files (wp-config.php.save, wp-config.php.orig) in the web root after a manual edit over SFTP; trusting a hosting provider’s “we handle security” marketing without verifying the actual file permissions via SSH; and blocking access only in .htaccess on Apache while running Nginx in front as a reverse proxy, where .htaccess rules are silently ignored and provide zero protection.
Blocking Access at the Web Server Level
Placement and permissions handle the filesystem side; the web server config should also explicitly deny access as a second layer. On Apache, inside the site’s .htaccess or vhost config:
<Files wp-config.php> Require all denied </Files>
On Nginx, a location block matching wp-config.php returning 403 or 444. Neither replaces correct permissions and placement — they’re a second layer, not a substitute, and this is exactly the kind of misconfiguration that security misconfiguration checks under OWASP Top 10 are designed to catch.
How This Fits Into a Broader Hardening Routine
wp-config.php hardening rarely happens in isolation. It usually comes up alongside reviewing WordPress admin account roles, plugin update cadence, and general WordPress admin panel hardening. Because permission regressions and stray backup files are invisible until someone requests the exact path, catching them requires something that checks continuously rather than once — which is the kind of drift that recurring WordPress vulnerability audits are built to surface before an attacker finds it first.
FAQ
Does moving wp-config.php outside the web root break WordPress updates?
No. WordPress core, plugin, and theme updates all go through the normal wp-load.php bootstrap, which already checks one directory above the site root for the config file. Auto-updates and the dashboard updater work identically either way.
Is 644 permissions ever acceptable for wp-config.php?
Only in single-tenant environments where no other local user or process on the server could conceivably read the file — for instance an isolated container running only that one site. On any shared hosting environment, or any server with multiple sites or user accounts, 644 should be treated as a finding to fix immediately, not a judgment call.
Can a security scanner detect a misconfigured wp-config.php remotely?
It can detect the symptoms — a server that serves .php files as plain text, a stray wp-config.php.bak returning a 200 instead of a 404, or missing security headers that suggest a broader misconfiguration — without needing filesystem access. That’s different from confirming actual file permissions, which requires server-side access, so remote scanning and a manual permissions audit answer different halves of the same question.
Get the placement and permissions right once, verify them on a schedule, and treat any editor backup file in the web root as an incident rather than a curiosity — that combination closes off one of the few WordPress risks that doesn’t depend on a plugin vulnerability or a weak password.
