The wp-config.php file is the single most important file in your WordPress installation. It contains your database credentials, authentication keys, and security constants that control how WordPress behaves at its core.
Yet most WordPress administrators never touch it after the initial setup — leaving critical security features disabled by default.
In this guide, we’ll walk through 15 essential wp-config.php settings that significantly improve your site’s security posture. Each setting includes the exact code to add, an explanation of what it does, and the real-world attack it prevents.
Where Is wp-config.php and How to Edit It
The wp-config.php file is located in the root directory of your WordPress installation, typically at:
/var/www/html/wp-config.php
— or —
~/public_html/wp-config.php
How to edit it:
- Connect to your server via SFTP (using FileZilla, Cyberduck, etc.) or SSH
- Download
wp-config.phpas a backup before making changes - Edit the file with a plain text editor (not Microsoft Word)
- Upload the modified file back to the server
Important: Always back up wp-config.php before editing. A syntax error in this file will take your entire site offline.
All constants should be added above the line that says:
/* That's all, stop editing! Happy publishing. */
Part 1: Critical Security Settings
1. Disable Debug Mode in Production
What it does: When WP_DEBUG is enabled, WordPress displays PHP errors, warnings, and notices directly on your pages. This exposes internal file paths, function names, and database query details to anyone visiting your site.
The risk: Attackers use debug output to map your server’s directory structure, identify installed plugins, and find vulnerable code paths.
When you run a security scan with FunSentry, the scanner checks your homepage for visible PHP errors and warnings — a clear sign that debug mode is leaking information to the public.
// ✅ Production settings — disable all debug output
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_DISPLAY', false );
define( 'WP_DEBUG_LOG', false );
If you need to debug issues on a production site, log errors to a file instead of displaying them:
// ✅ Safe debugging — log to file, never display
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_DISPLAY', false );
define( 'WP_DEBUG_LOG', true ); // Logs to /wp-content/debug.log
Warning: If you enable WP_DEBUG_LOG, make sure /wp-content/debug.log is not publicly accessible. Block it via .htaccess or Nginx:
# Block access to debug.log
<Files debug.log>
Order Allow,Deny
Deny from all
</Files>
2. Disable File Editing from the Dashboard
What it does: WordPress includes a built-in code editor at Appearance → Theme File Editor and Plugins → Plugin File Editor that allows administrators to modify PHP files directly from the browser.
The risk: If an attacker gains admin access (through a stolen password, session hijacking, or a plugin vulnerability), they can inject malicious code into your theme or plugin files — creating backdoors, redirects, or data-stealing scripts — all without needing FTP access.
// ✅ Disable the built-in file editor
define( 'DISALLOW_FILE_EDIT', true );
For even stricter control, you can also prevent plugin and theme installations/updates from the dashboard:
// ✅ Prevent all file modifications from the dashboard
define( 'DISALLOW_FILE_MODS', true );
Note: With DISALLOW_FILE_MODS enabled, you’ll need to update plugins and themes via SFTP, WP-CLI, or a deployment pipeline. This is the recommended approach for production sites.
3. Force SSL for Admin and Logins
What it does: Forces all admin dashboard pages and login forms to use HTTPS encryption.
The risk: Without this setting, an administrator logging in over an unsecured network (e.g., coffee shop Wi-Fi) could have their credentials intercepted via a man-in-the-middle attack.
// ✅ Force HTTPS for admin and login pages
define( 'FORCE_SSL_ADMIN', true );
define( 'FORCE_SSL_LOGIN', true );
Prerequisite: Your site must have a valid SSL certificate installed. If you’re not sure, run a scan at FunSentry — the SSL/TLS module checks your certificate validity, expiration date, and HTTPS redirect behavior.
4. Set Authentication Keys and Salts
What it does: WordPress uses these eight cryptographic keys to encrypt information stored in user cookies. They make it significantly harder for attackers to forge or hijack user sessions.
The risk: Default or empty keys mean weaker cookie encryption. If an attacker obtains a session cookie, weak keys make it easier to decode or brute-force.
// ✅ Generate unique keys at: https://api.wordpress.org/secret-key/1.1/salt/
define( 'AUTH_KEY', 'put your unique phrase here' );
define( 'SECURE_AUTH_KEY', 'put your unique phrase here' );
define( 'LOGGED_IN_KEY', 'put your unique phrase here' );
define( 'NONCE_KEY', 'put your unique phrase here' );
define( 'AUTH_SALT', 'put your unique phrase here' );
define( 'SECURE_AUTH_SALT', 'put your unique phrase here' );
define( 'LOGGED_IN_SALT', 'put your unique phrase here' );
define( 'NONCE_SALT', 'put your unique phrase here' );
Generate fresh keys using the official WordPress API:
https://api.wordpress.org/secret-key/1.1/salt/
Visit that URL, copy the output, and paste it into your wp-config.php, replacing any existing keys.
Best practice: Rotate these keys periodically (every 6–12 months) or immediately after a suspected security breach. Changing the keys will force all currently logged-in users to re-authenticate.
5. Change the Database Table Prefix
What it does: By default, WordPress uses wp_ as the prefix for all database tables (e.g., wp_users, wp_options). Changing this makes SQL injection attacks harder, since attackers must guess the table names.
The risk: Automated SQL injection tools assume default table names. A custom prefix breaks these automated attacks.
// ✅ Use a custom table prefix (set during installation)
$table_prefix = 'fs29x_';
Important: This must be set before WordPress is installed. Changing it on an existing installation requires renaming all database tables and updating references in wp_options and wp_usermeta. Use a plugin like “Brozzme DB Prefix” if you need to change it post-installation.
Part 2: Access Control Settings
6. Block Direct Access to wp-config.php
The wp-config.php file itself must never be accessible via HTTP. FunSentry’s sensitive files scanner specifically checks if wp-config.php, wp-config.php.bak, wp-config.php~, and .wp-config.php.swp are publicly downloadable — and flags them as critical severity if found.
For Apache (.htaccess):
# Protect wp-config.php from direct access
<Files wp-config.php>
Order Allow,Deny
Deny from all
</Files>
For Nginx:
location = /wp-config.php {
deny all;
access_log off;
log_not_found off;
}
Bonus: Move wp-config.php one directory above your WordPress root. WordPress automatically checks the parent directory:
/home/user/wp-config.php ← WordPress finds it here
/home/user/public_html/ ← WordPress root (no wp-config.php here)
/home/user/public_html/wp-admin/
/home/user/public_html/wp-content/
This way, even if your web server is misconfigured, wp-config.php is outside the document root and cannot be served to browsers.
7. Disable User Registration (If Not Needed)
What it does: Controls whether new users can register accounts on your site.
The risk: Open registration allows attackers to create subscriber-level accounts, which can then be escalated through plugin vulnerabilities or used for spam.
Check this in the WordPress admin under Settings → General → Membership. If you don’t need public registration, uncheck it.
You can also enforce it in wp-config.php by ensuring the registration page is not accessible. FunSentry checks both the login page (/wp-login.php) and registration endpoint (/wp-login.php?action=register) and reports their status.
8. Limit Post Revisions
What it does: WordPress stores a complete copy of every saved revision for each post. On a busy site, this can lead to thousands of unnecessary database rows.
The risk: While not a direct security threat, a bloated database is slower to query and slower to back up. In a security incident, a lean database is faster to restore.
// ✅ Limit to 5 revisions per post
define( 'WP_POST_REVISIONS', 5 );
// Or disable revisions entirely
define( 'WP_POST_REVISIONS', false );
9. Configure Auto-Save Interval
What it does: WordPress auto-saves posts every 60 seconds by default. This can be extended to reduce database writes.
// ✅ Auto-save every 5 minutes (300 seconds)
define( 'AUTOSAVE_INTERVAL', 300 );
10. Disable WP-Cron (Use System Cron Instead)
What it does: WordPress has a built-in cron system (wp-cron.php) that triggers scheduled tasks (like publishing scheduled posts) on every page load. This is inefficient and creates a publicly accessible endpoint.
The risk: wp-cron.php can be abused to trigger resource-intensive tasks repeatedly, causing performance degradation. FunSentry checks if /wp-cron.php is publicly accessible and reports it.
// ✅ Disable WordPress's built-in cron
define( 'DISABLE_WP_CRON', true );
Then set up a real system cron job (runs every 15 minutes):
# Add to crontab (crontab -e)
*/15 * * * * wget -q -O - https://yoursite.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
Or with WP-CLI:
*/15 * * * * cd /path/to/wordpress && wp cron event run --due-now > /dev/null 2>&1
Part 3: Database and Performance Security
11. Set Custom Database Connection Details
If your database is on a separate server, always use an explicit host rather than localhost:
// ✅ Explicit database connection
define( 'DB_HOST', '10.0.1.50:3306' ); // Internal IP, not public
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );
Security note: Never use root as the database user. Create a dedicated MySQL user with only the privileges WordPress needs:
-- Create a dedicated database user
CREATE USER 'wp_funsentry'@'10.0.1.%' IDENTIFIED BY 'strong_random_password_here';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX
ON wordpress_db.* TO 'wp_funsentry'@'10.0.1.%';
FLUSH PRIVILEGES;
12. Increase Memory Limits
What it does: Sets the maximum memory PHP can use for WordPress operations. Low memory can cause white screens, failed updates, and incomplete backups.
// ✅ Standard memory limit
define( 'WP_MEMORY_LIMIT', '256M' );
// ✅ Admin tasks may need more (imports, updates)
define( 'WP_MAX_MEMORY_LIMIT', '512M' );
13. Define the Trash Auto-Empty Interval
What it does: WordPress keeps deleted posts and pages in the trash. By default, trash is emptied after 30 days.
// ✅ Empty trash after 7 days
define( 'EMPTY_TRASH_DAYS', 7 );
// Disable trash entirely (items are permanently deleted)
define( 'EMPTY_TRASH_DAYS', 0 );
Warning: Setting this to 0 means clicking “Delete” is permanent — there’s no undo. This is appropriate for high-security environments where you don’t want recoverable data lingering.
Part 4: Advanced Hardening
14. Block External HTTP Requests (Selective)
What it does: Prevents WordPress from making outbound HTTP requests to external servers. This blocks phone-home features, auto-updates, and external API calls.
// Block ALL external requests (strict mode)
define( 'WP_HTTP_BLOCK_EXTERNAL', true );
// Allow specific hosts (comma-separated)
define( 'WP_ACCESSIBLE_HOSTS', 'api.wordpress.org,downloads.wordpress.org,*.github.com' );
Use case: If your site has been compromised, malware often phones home to a command-and-control server. Blocking external requests contains the damage while you clean the infection.
Warning: This breaks auto-updates and plugin/theme installation. Only use on sites with a manual deployment workflow.
15. Define a Custom Content Directory
What it does: Moves the wp-content directory to a custom location with a non-standard name, making it harder for attackers to target.
// ✅ Move wp-content to a custom directory
define( 'WP_CONTENT_DIR', dirname(__FILE__) . '/assets' );
define( 'WP_CONTENT_URL', 'https://yoursite.com/assets' );
Attackers commonly probe /wp-content/plugins/ and /wp-content/uploads/ for known vulnerabilities and directory listings. Renaming the directory breaks these automated scans.
Note: Some poorly coded plugins may break if they hardcode /wp-content/ paths. Test thoroughly after making this change.
The Complete Secure wp-config.php Template
Here’s a consolidated template with all the security settings covered in this guide:
<?php
/**
* WordPress Security-Hardened Configuration
* Generated with guidance from FunSentry (https://www.funsentry.com)
*/
// ── Database Settings ──
define( 'DB_NAME', 'your_database_name' );
define( 'DB_USER', 'your_database_user' ); // Never use 'root'
define( 'DB_PASSWORD', 'your_strong_password' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );
// ── Custom Table Prefix ──
$table_prefix = 'fs29x_'; // Change from default 'wp_'
// ── Authentication Keys and Salts ──
// Generate at: https://api.wordpress.org/secret-key/1.1/salt/
define( 'AUTH_KEY', 'generate-unique-key-here' );
define( 'SECURE_AUTH_KEY', 'generate-unique-key-here' );
define( 'LOGGED_IN_KEY', 'generate-unique-key-here' );
define( 'NONCE_KEY', 'generate-unique-key-here' );
define( 'AUTH_SALT', 'generate-unique-key-here' );
define( 'SECURE_AUTH_SALT', 'generate-unique-key-here' );
define( 'LOGGED_IN_SALT', 'generate-unique-key-here' );
define( 'NONCE_SALT', 'generate-unique-key-here' );
// ── Security Hardening ──
define( 'WP_DEBUG', false ); // No debug in production
define( 'WP_DEBUG_DISPLAY', false ); // Never display errors
define( 'WP_DEBUG_LOG', false ); // No debug log file
define( 'DISALLOW_FILE_EDIT', true ); // Disable theme/plugin editor
define( 'DISALLOW_FILE_MODS', true ); // Disable all file modifications
define( 'FORCE_SSL_ADMIN', true ); // Force HTTPS for admin
define( 'FORCE_SSL_LOGIN', true ); // Force HTTPS for login
// ── Performance & Maintenance ──
define( 'WP_POST_REVISIONS', 5 ); // Limit revisions
define( 'AUTOSAVE_INTERVAL', 300 ); // Auto-save every 5 min
define( 'EMPTY_TRASH_DAYS', 7 ); // Empty trash after 7 days
define( 'DISABLE_WP_CRON', true ); // Use system cron instead
define( 'WP_MEMORY_LIMIT', '256M' ); // PHP memory limit
define( 'WP_MAX_MEMORY_LIMIT', '512M' ); // Admin memory limit
/* That's all, stop editing! Happy publishing. */
How to Verify Your Settings Are Working
After applying these changes, verify that your configuration is effective:
1. Run a FunSentry Scan
Visit www.funsentry.com and scan your site. The scanner checks for:
- Debug output leaks — Detects PHP errors, warnings, and notices on your homepage
- Sensitive file exposure — Checks if
wp-config.php,.env,debug.log, and backup files are publicly accessible - User enumeration — Tests if
/?author=1reveals usernames - Login page exposure — Reports if
/wp-login.phpis accessible - Registration page status — Checks if open registration is enabled
- WP-Cron exposure — Verifies if
/wp-cron.phpis publicly reachable
2. Manual Verification
# Test debug mode (should NOT show PHP errors)
curl -s https://yoursite.com | grep -i "fatal error\|warning\|notice\|deprecated"
# Test wp-config.php protection (should return 403)
curl -I https://yoursite.com/wp-config.php
# Test wp-config backup files (should return 403 or 404)
curl -I https://yoursite.com/wp-config.php.bak
curl -I https://yoursite.com/wp-config.php~
# Test debug.log protection (should return 403 or 404)
curl -I https://yoursite.com/wp-content/debug.log
# Test user enumeration (should NOT redirect to /author/username/)
curl -I https://yoursite.com/?author=1
Common Mistakes to Avoid
| Mistake | Why It’s Dangerous | Fix |
|---|---|---|
Leaving WP_DEBUG as true in production | Exposes file paths and internal errors | Set to false |
Using root as the DB user | A compromised site gives full database server access | Create a dedicated user with minimal privileges |
Default wp_ table prefix | Automated SQL injection tools target default names | Use a random prefix |
| Never rotating auth keys | Compromised keys remain valid indefinitely | Regenerate every 6–12 months |
debug.log publicly accessible | Contains SQL queries, file paths, plugin errors | Block via .htaccess or delete after debugging |
Storing wp-config.php backups in webroot | Files like wp-config.php.bak are downloadable | Never store backups in the document root |
| Leaving the theme/plugin editor enabled | An admin account compromise becomes a full code execution compromise | Set DISALLOW_FILE_EDIT to true |
Summary
| Setting | Constant | Recommended Value |
|---|---|---|
| Debug mode | WP_DEBUG | false |
| Debug display | WP_DEBUG_DISPLAY | false |
| File editor | DISALLOW_FILE_EDIT | true |
| File modifications | DISALLOW_FILE_MODS | true |
| SSL admin | FORCE_SSL_ADMIN | true |
| Table prefix | $table_prefix | Custom (not wp_) |
| Post revisions | WP_POST_REVISIONS | 5 |
| WP-Cron | DISABLE_WP_CRON | true |
| Auth keys | All 8 keys/salts | Unique random values |
| Memory limit | WP_MEMORY_LIMIT | 256M |
The wp-config.php file is your first line of defense. These 15 settings take about 10 minutes to implement and immediately close some of the most commonly exploited misconfigurations in WordPress.
Don’t guess whether your settings are working — verify them. Run a free scan at FunSentry to check your debug output, sensitive file exposure, user enumeration, and more.
This article was written by the FunSentry security research team. FunSentry is a free online WordPress security scanner that performs passive checks on debug mode, sensitive file exposure, user enumeration, login page access, and other wp-config.php-related security issues. Scan your site now to verify your configuration.
