Most hacked WordPress sites are not victims of clever targeted attacks. They run an outdated plugin, reuse a password, or leave a default setting in place, and automated scanners find them within hours or days. Hardening means removing those easy openings. None of the steps below is exotic, and together they block the large majority of automated attacks.
Use this as a checklist. Each item says what to do and how to verify it. If you suspect a compromise has already happened, go straight to WordPress site hacked recovery.
1. Updates and software hygiene
- Keep core, plugins and themes updated. Vulnerabilities in plugins are the leading way sites are compromised. Check pending updates with WP-CLI:
wp core check-update
wp plugin list --update=available
wp theme list --update=available
Enable automatic updates for security releases of core (on by default for minor releases) and consider automatic updates for plugins you trust:
wp plugin auto-updates enable --all # or name specific plugins
- Delete unused plugins and themes, not just deactivate them. Inactive code can still be exploited if it is reachable by URL.
wp plugin delete hello-dollyandwp theme delete twentytwentytwo, keeping one default theme as a fallback. - Use only plugins from sources you trust, with recent updates and active maintenance. Avoid "nulled" copies of premium plugins; they commonly contain backdoors.
- Run a supported PHP version. Old PHP versions stop receiving security fixes. Check what is supported at php.net and update after testing on a staging copy.
- Keep the server patched if you manage a VPS:
sudo apt update && sudo apt upgradeon a regular schedule, and enable unattended security updates.
2. Logins and accounts
- Use unique, long passwords for WordPress, hosting, database, SFTP and email, stored in a password manager. Reused passwords from other breaches are a very common way in.
- Enable two-factor authentication for every administrator and editor, using an authenticator app rather than SMS.
- Do not use the username
admin, and avoid exposing author usernames. Check users:wp user list --fields=ID,user_login,roles. Remove accounts you do not recognize. - Give people the lowest role they need. Editors do not need Administrator. Review roles quarterly.
- Limit login attempts and block brute-force. A rate-limiting plugin, your web application firewall, or fail2ban on the server can all do this. For nginx, limit requests to the login endpoint:
limit_req_zone $binary_remote_addr zone=wplogin:10m rate=5r/m;
location = /wp-login.php {
limit_req zone=wplogin burst=5 nodelay;
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
- Disable XML-RPC if you do not use it. It enables password-guessing in bulk (via
system.multicall). If no app needs it, block it. In Apache:
<Files xmlrpc.php>
Require all denied
</Files>
In nginx: location = /xmlrpc.php { deny all; }. Note that some services (for example the Jetpack plugin, and older mobile apps) use XML-RPC, so confirm before blocking.
3. wp-config.php and WordPress settings
- Disable the built-in file editor so that a stolen admin session cannot edit PHP files from the dashboard:
define( 'DISALLOW_FILE_EDIT', true );
Use DISALLOW_FILE_MODS only if you deploy updates another way, because it also blocks plugin and core updates from the dashboard.
- Force HTTPS for admin and logins:
define( 'FORCE_SSL_ADMIN', true );
- Regenerate the authentication keys and salts (they are in
wp-config.php). New values log out all users, which is useful after a suspected compromise. Generate values from the WordPress.org secret-key service or with WP-CLI:wp config shuffle-salts. - Move
wp-config.phpout of reach. WordPress will read it from one directory above the web root. At minimum, deny web access to it, and never leave backups such aswp-config.php.bak,wp-config.oldor.zipfiles in the web root, as these are downloadable as plain text. - Turn off debug output in production (
WP_DEBUG_DISPLAYfalse), as in the white screen of death guide.
4. File permissions and server configuration
- Set conservative file permissions. The usual recommendation is 644 for files and 755 for directories, with
wp-config.phpat 640 or 600 where the web server user can still read it. Avoid 777 anywhere.
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
chmod 640 /var/www/html/wp-config.php
Make sure files are owned by the deploy user rather than the web server user where possible, so that a PHP compromise cannot rewrite core code.
- Block PHP execution in uploads, since attackers often upload a PHP file disguised as an image. For Apache, add to
wp-content/uploads/.htaccess:
<FilesMatch "\.(php|php\d|phtml|phar)$">
Require all denied
</FilesMatch>
For nginx, within the server block:
location ~* ^/wp-content/uploads/.*\.(php|phtml|phar)$ { deny all; }
- Disable directory listing:
Options -Indexesfor Apache and make sureautoindex off;in nginx. - Hide sensitive files such as
.git,.env,readme.html, backup files anddebug.log:
location ~ /\.(?!well-known) { deny all; }
location ~* \.(sql|bak|old|log|zip|tar|gz)$ { deny all; }
Adjust the last rule if you legitimately serve archives.
- Use a unique database user with only the privileges WordPress needs, and never reuse the database password elsewhere. Change the default table prefix only on new installs; it is not a defense on its own.
5. HTTPS and security headers
- Serve everything over HTTPS and keep the certificate valid; see how to renew SSL and automate it. Check it with the SSL Checker. The WordPress HTTPS migration guide covers moving an existing site.
- Add security headers at the web server or CDN. A sensible starting set for most WordPress sites:
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000" always;
Content Security Policy is powerful but easy to break on WordPress, because themes and plugins inject inline scripts. Test it in report-only mode first. Verify with the Security Headers Checker and HSTS Checker. The HTTP security headers guide explains each header, and content security policy guide covers CSP.
- Publish a security contact with a
/.well-known/security.txtfile so researchers know where to report problems. Check yours with the security.txt Checker.
6. Backups, monitoring and recovery
- Keep automated, off-site backups of files and database, retained for at least a few weeks, and test a restore. A backup stored only on the same server is lost along with the server. Verify by restoring to a staging site, not by trusting a "backup completed" message.
Beyond the numbered list:
- File integrity checks.
wp core verify-checksumscompares core files to the official release, andwp plugin verify-checksums --alldoes the same for plugins from WordPress.org. Run these weekly from cron and alert on any difference. - Uptime and content monitoring. An outage or a defaced page is often your first sign of a compromise. Use the uptime monitor with a keyword check on a phrase that should appear on your page, and with SSL alerts so an expiring certificate does not surprise you.
- Blocklist status. If search engines or email providers flag your domain, you will see traffic or delivery problems. Check the Blacklist Checker periodically.
- A web application firewall (host-level, a security plugin or a CDN) can filter known exploit patterns. It supplements updates; it does not replace them.
- Logs. Know where to find access logs and watch for repeated POSTs to
wp-login.phpandxmlrpc.php, or requests to files you do not recognize.
What to do first on a neglected site
If the list feels long, do these five things today: update everything, delete unused plugins, enable two-factor authentication for admins, set up off-site backups with a tested restore, and add monitoring. Then work down the rest.
Next steps
- Check your headers with the Security Headers Checker and HSTS Checker.
- Verify HTTPS with the SSL Checker.
- Add alerts with the uptime monitor.
- Learn the recovery procedure in WordPress site hacked recovery.
- Read the e-commerce site security checklist if you take payments.
FAQ
Do I need a security plugin?
Not necessarily, but one can add useful layers such as login rate limiting, file change alerts and firewall rules. Pick one reputable plugin rather than several that overlap, and do not treat it as a substitute for updates and backups.
Is changing the login URL worth it?
It reduces noise from automated bots but is not real security, because the URL can still be discovered. Strong passwords, two-factor authentication and rate limiting matter more.
How often should I update plugins?
Apply security updates as soon as you reasonably can, ideally within days. For major updates, test on staging first. Automatic updates are reasonable for small, well-maintained plugins.
Will hardening break my site?
Some steps can, particularly blocking XML-RPC, a strict Content Security Policy or DISALLOW_FILE_MODS. Make changes one at a time, test, and keep a backup so you can revert quickly.
Is HTTPS enough to make my site secure?
No. HTTPS protects data in transit, but it does nothing against outdated plugins, weak passwords or malicious uploads. Treat it as one item on this list.
Get notified when this guide updates
Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.
This page is general information written by our editorial team and updated when documentation changes. Servers and providers differ, so test changes safely first. See our editorial policy and disclaimer.