
WordPress Hardening: The Complete Checklist
Hardening is removing attack surface, not adding tools. This is the prioritised list of 25 items across three urgency tiers that you can actually finish. If your site is currently compromised, run the cleanup walkthrough first; the highest-impact step below is 2FA, and the 2FA setup walkthrough covers the rollout.
What hardening actually means (and what it doesn't)
TL;DR: WordPress hardening means removing attack surface, not bolting on tools. Work the nine REQUIRED items (updates, 2FA, unique admin passwords, forced admin HTTPS, daily offsite backups) and you are already harder to attack than most sites on the internet. The full 25-item checklist below takes a single 60-minute sprint, and almost every fix is permanent.
You don't need to be uncrackable. You need to be inconvenient. WordPress hardening is the practice of removing unnecessary attack surface: closing known vulnerabilities, hiding information that helps an attacker plan, and limiting what they can do if they get in. It's a posture, not a tool. You can run three security plugins on a poorly configured site and still get owned. A well-hardened site without any security plugin is harder to attack than the same site with one bolted on.
The reason this works is that almost every real-world attack against a WordPress site is automated and run at scale. Patchstack's State of WordPress Security 2025 logged 7,966 new vulnerabilities across the WordPress ecosystem in 2024, an average of 22 a day, with plugins responsible for 96% of them and 43% of the total requiring no authentication to exploit. Wordfence blocked 55 billion password attacks and 54 billion malicious requests in the same year. The bots running those attacks are not creative. They probe every site with a known misconfiguration and move on the moment yours fails the checklist.
The checklist below is split into three urgency tiers. REQUIRED is what an attacker checks first: nine items, mostly under ten minutes each, zero cost. RECOMMENDED is ten one-time config changes that stay fixed forever; budget roughly an hour. ADVANCED is six items that need a working understanding of the trade-off before you flip the switch. Stop at REQUIRED and you're already in better shape than most WordPress sites on the internet. Work the whole list and your site falls out of the easy-target pool entirely.
REQUIRED — do these before anything else
Nine items. Most take under ten minutes. These are the entry points an attacker checks first. If you've done all nine, you've eliminated the most common ways a WordPress site gets compromised in 2026.
Item 1 — Update core, plugins, and themes. Open Dashboard → Updates and run everything pending. Wordfence's 2024 annual report flagged that 35% of the year's vulnerabilities were still unpatched in 2025; the patch is almost always there, it just hasn't been applied. Item 2 — Enable plugin auto-updates. Plugins → Plugins → Enable auto-updates per plugin, or run a weekly manual review on a calendar reminder. Item 3 — Delete inactive plugins and themes. Deactivated does not mean inert; the files still sit on disk and can still be exploited by a vulnerability in that plugin's code. If you're not using it, delete it. The broader pattern of how outdated plugins become entry points lives at plugin vulnerabilities; how plugin vulnerabilities work covers the CVE disclosure-to-exploit lifecycle and the five-hour window that makes patching speed matter.
Item 4 — Run PHP 8.2 or newer. Older PHP versions have stopped receiving security patches; running PHP 7.4 in 2026 means you're on software that hasn't seen a security update in years. Most hosts switch versions from the control panel in a single click. Do it, then test the front end and admin for warnings before moving on. WordPress 6.8 (April 2025) also upgraded password hashing from phpass to bcrypt and switched application and reset keys to BLAKE2b. If you're on 6.8 or newer, every user's password rehashes silently on next login. No action needed beyond staying current.
Item 5 — Enable two-factor authentication on every admin account. This is the single highest-impact item on the list. 2FA defeats credential stuffing attacks entirely; a leaked password is useless without the second factor. The free official Two Factor plugin or Wordfence Login Security each take about five minutes to set up. Full walkthrough at the 2FA setup guide. Item 6 — Use a unique, high-entropy password for every admin. Sixteen-plus random characters from a password manager. Reused passwords get pulled from breached databases and tried against WordPress logins by the bots automatically. A unique password means a leak somewhere else can't unlock your site. Item 7 — Audit your user list. Users → All Users; delete anything you don't recognise, especially with Administrator role. Fewer admins, smaller surface, fewer accounts to keep 2FA on, and fewer targets for user enumeration to point a botnet at.
Item 8 — Force HTTPS for admin sessions. Add `define('FORCE_SSL_ADMIN', true);` to wp-config.php so every admin request runs over HTTPS and auth cookies carry the Secure flag. Prerequisite: a working SSL certificate, which is free from Let's Encrypt on any decent host. If you also want a full site-wide HTTP-to-HTTPS redirect (you should), the HTTPS redirect guide has the host-level config. Without this, an attacker on the same network as you (coffee shop, hotel wifi) can sniff your session cookie and impersonate you in the admin.
Item 9 — Daily offsite backups. Automated, daily, stored on a different server than your site. UpdraftPlus pushing to S3 or Backblaze B2 is the cheap option; BlogVault, Jetpack VaultPress, or your host's managed backup is the no-thought option. Test the restore quarterly: a backup you've never tested is a hypothesis, not a backup. When something goes wrong (and over a long enough timeline, something always does), the gap between "restore yesterday" and "start over from a stale export" is the entire game. Daily, not weekly: a weekly cadence means you can lose up to seven days of orders, comments, or new content.
RECOMMENDED — do these this week
Ten items. Most are one-time config changes that stay fixed forever. If you did REQUIRED yesterday, do RECOMMENDED today: roughly 45 to 60 minutes total.
Item 10 — Disable file editing from the dashboard. Add `define('DISALLOW_FILE_EDIT', true);` to wp-config.php. An attacker who gets into the admin can no longer drop malicious code into your theme files from the Appearance editor; they have to find another way in, which buys you time and leaves a noisier audit trail. Item 11 — Turn off debug output in production. Set `define('WP_DEBUG', false);` in wp-config.php to stop stack traces and absolute file paths from leaking to public visitors when something errors. Leave debugging on locally, off in production. Item 12 — Disable directory listing. Add `Options -Indexes` to the top of your root .htaccess file. Without it, any directory missing an index file returns a browsable list of every file inside, handy for attackers mapping your install and finding stray backups.
Item 13 — Block PHP execution in wp-content/uploads. WordPress never legitimately runs PHP from the uploads folder; any .php file there is a webshell in your uploads folder. The fix is a short .htaccess file inside uploads with a `FilesMatch` block denying php and phtm extensions. Full snippet and the Nginx equivalent live in the exposed files fix guide. This single rule shuts down a huge class of post-exploit persistence. Item 14 — File permissions. Directories at 755, files at 644, wp-config.php at 400 or 440. The pattern is a single `find` plus `chmod` against your install over SSH, then a separate `chmod 400 wp-config.php`. The exact commands are in the official WordPress hardening doc. If you don't have SSH access, ask your host; most managed providers can set this for you in a support ticket. Permissions of 777 anywhere in your install are a hard red flag.
Item 15 — Disable XML-RPC if you don't use it. XML-RPC (XML Remote Procedure Call) is the most-abused brute-force endpoint on a default WordPress install: a single request to /xmlrpc.php can try thousands of password combinations in one POST. Modern Jetpack (2024 onward) primarily uses the REST API and falls back to XML-RPC only in edge cases, so disabling it is safe for most users. Either install the Disable XML-RPC plugin (one click) or follow the XML-RPC fix guide. Item 16 — Block REST API user enumeration. Visiting `/wp-json/wp/v2/users` on a default install returns a JSON list of every administrator username, half of a brute-force attempt handed over for free. A short filter in a must-use plugin removes the endpoint without breaking Gutenberg; the working code is in the REST API security walkthrough. Item 17 — Block version-disclosure files. Deny public access to readme.html and license.txt; both leak your WordPress version and let an attacker pre-select which CVEs (Common Vulnerabilities and Exposures) to throw at you. Pattern lives in the exposed files fix guide.
Item 18 — Add security headers. Five headers, all sent from your server. `X-Frame-Options: SAMEORIGIN` blocks clickjacking. `X-Content-Type-Options: nosniff` stops MIME-sniffing attacks. `Referrer-Policy: strict-origin-when-cross-origin` limits what referrer data leaks to other sites. `Permissions-Policy` disables browser APIs you don't use (geolocation, microphone, camera). `Strict-Transport-Security` enforces HTTPS at the browser level. They live in .htaccess above the WordPress block on Apache, or in the server config on Nginx. Full snippet at the security headers fix guide. None of these need application changes; they're pure server config and they stay fixed forever once added. Item 19 — Disable application passwords if you don't use them. Application passwords (introduced in WordPress 5.6) are HTTP Basic Auth tokens for the REST API. They bypass 2FA by design: useful if you have a real REST integration, dangerous dead weight if you don't. Disable with `add_filter('wp_is_application_passwords_available', '__return_false');` in a must-use plugin.
ADVANCED — higher-risk sites or when you're comfortable
Six items. Higher complexity, real trade-offs, or server-level access required. Do REQUIRED and RECOMMENDED first. Advanced doesn't mean dangerous; it means you need to understand what you're trading before you flip the switch.
Item 20 — Move wp-config.php above the document root. WordPress checks the parent directory for wp-config.php, so relocating it one level up means a server misconfiguration that disables PHP parsing won't expose your database credentials as plain text. Shared hosting often doesn't allow this. If you can't write outside the public web directory, skip the item. Item 21 — Content-Security-Policy (CSP). A correctly tuned CSP header blocks injected scripts at the browser level, but a wrong one will break your admin, your page builder, or both. Patchstack's own headers guide warns that mindlessly adding CSP can break the website. Roll it out in report-only mode first, watch the browser console and the report endpoint for two weeks, then promote to enforcing once you're sure your real traffic isn't tripping it.
Item 22 — IP-whitelist /wp-admin. Adding `Require ip 203.0.113.4` style rules to a Location block restricts admin access to known networks. Works well for a fixed-office team; falls apart the moment you need to log in from a hotel, a client's office, or a phone hotspot. Don't use this on a site you manage remotely. Item 23 — HSTS preload. Submitting your domain to the HSTS preload list means every major browser will refuse HTTP connections to your domain for years, even if you remove the header later. This is a one-way door. Run HSTS without preload for a few months, confirm nothing on a subdomain or third-party integration breaks, and only then submit.
Item 24 — Salt rotation: break-glass only. Most checklists tell you to rotate the AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY and NONCE_KEY values in wp-config.php on a schedule. This is wrong. Snicco's technical deep-dive is clear: WordPress salts sign temporary things like auth cookies, nonces, password reset tokens, and "remember me" cookies. They don't protect stored passwords. Rotating them logs every user out instantly, breaks every active password-reset link, and can permanently corrupt data in any plugin that encrypts with them (what plugins can encrypt in the database covers the data side). Rotate salts immediately after a confirmed compromise; that's the legitimate reason to invalidate every existing session at once. Never on a calendar.
Item 25 — Web Application Firewall. Cloudflare's free tier in front of your site gives you DDoS protection, basic WAF rules, and bot-fight mode that filters a lot of automated traffic before it ever reaches your server. It's a sensible layer, not a replacement for the items above. If you want a WordPress-aware WAF specifically, Wordfence (plugin-level, sees inside WordPress) and Sucuri (managed, sits in front) both work. The security tools comparison covers what each catches and where they overlap.
Two things most checklists get wrong
The wp_ table prefix rename. Most WordPress hardening checklists still include it. Wordfence's 2016 research, which still holds because the SQL standard hasn't changed, showed that SQL injection attacks don't guess your table names. They query the `information_schema` database, which any MySQL user can read, and get the full list of your tables in a single statement. The literal prefix is irrelevant. Renaming wp_ to something custom adds migration risk, breaks a handful of plugins that hardcode the prefix string, and gives you exactly zero protection against the attack it's supposedly defending. It's the hardening world's version of hiding your spare key under the mat. Skip this.
Hiding /wp-login.php behind a custom URL. This reduces noise from the dumbest bots (the ones that only probe the literal default path) but provides zero protection against anything targeted. WPScan, WPSeku, and every other WordPress fingerprinting tool detect installs from a dozen other signals: the generator meta tag, /wp-content/ asset paths, the /wp-json/ REST root, default theme directory names, even predictable image filenames. The bot follows those signals to your renamed login page in seconds. Worth doing once you have 2FA in place as noise reduction in your access logs. Not worth doing instead of 2FA. If you're swapping a real lock for a painted door, you've made yourself less safe, not more.
The reason to be explicit about dropping these two is checklist fatigue. Every item you add that doesn't actually reduce risk displaces an item that does. A hardening pass is finite: you have an hour, a weekend, a sprint. Spend it on items where the threat model and the fix line up. Conviction over comprehensiveness.
The 60-minute hardening sprint
If you're starting from zero, this is the order that gives you the most protection per minute spent. Everything in REQUIRED, plus the highest-impact items from RECOMMENDED, sequenced for a single sitting.
Minutes 0 to 10. Run a free external scan on GuardingWP. Read the report; don't fix anything yet. The point of this opening block is a baseline: you want to know what's actually exposed before you start changing things, and you'll use the same scan again at the end to confirm each finding has dropped off.
Minutes 10 to 25. Authentication. Rotate your admin password to 16-plus random characters from a password manager. Install a 2FA plugin and enable it on every administrator account. Users → All Users; delete anyone you don't recognise. This block alone defeats the credential-stuffing attacks that account for the majority of automated WordPress break-ins.
Minutes 25 to 40. Open wp-config.php and add `define('DISALLOW_FILE_EDIT', true);` and `define('FORCE_SSL_ADMIN', true);`. Open your host control panel and confirm PHP 8.2 or newer is selected, then confirm daily backups are running and that you can see at least three restore points. Delete any inactive plugins or themes while you're in there. If you find anything in your file listing or plugins screen you don't recognise, treat it as suspicious; the find-malware-after-cleanup walkthrough covers what to check before deleting.
Minutes 40 to 60. Work through the scan findings in order of severity. The .htaccess items (directory listing, security headers, file blocking) are usually copy-paste from the linked fix guides, five minutes each. Run the scan again after each fix group so you can watch findings drop off the report. Finish by enabling plugin auto-updates and setting a monthly calendar reminder to log in and review.
That's it. You've done more for your site's security in one hour than 90% of WordPress site owners ever do, and most of the protection is permanent. The one thing you can't fix in a single sprint is keeping it that way: new plugin CVEs land daily, new admin accounts get added, configs drift. Weekly automated scanning catches the regressions before they become incidents. It's the difference between hardening as an event and hardening as a posture.
Related fix guides
Vulnerable Plugins Detected
One or more WordPress plugins has known security vulnerabilities. Learn how to find and update them.
Missing HTTP Security Headers
Your server isn't sending the HTTP headers that tell browsers how to protect your visitors. Learn which headers to add and how.
User Enumeration
WordPress is exposing your admin usernames via its REST API. Block it with one code snippet.
Login Page Exposed
Your WordPress login page is publicly accessible. Learn how to protect it from brute-force attacks.
Make this routine
GuardingWP Pro runs the same external scan every Monday and emails you when a new vulnerability lands — no more remembering to check. From $9/month, cancel anytime.
Scan your site to see which of these you still need →Or run a one-off check first: free scan, no account →
Prefer to have this handled for you? Get this fixed — Full Hardening ($149) →