Most WordPress hacks start with a simple door: a password that was guessed or that came from a leak on another site. Look at the access log of any WordPress site; you will probably see hundreds of POST requests to wp-login.php and xmlrpc.php from unknown addresses. These are bots, nearly free to run, and they visit every site.

The good news is that closing this door does not take ten plugins. Four layers are enough: a unique, long password, two-factor authentication, limits on failed attempts, and a smaller attack surface. We cover each below. If you still need an overall checklist, see the WordPress security checklist first.

Strong passwords, correctly defined#

A strong password means long and unique. "P@ssw0rd!" is not strong despite the symbol and number, because it is in every guessing list. A long random phrase used only for this site is far better.

  • Create a separate password for every administrator and editor, and use a password manager.
  • Change the database, hosting account and FTP passwords by the same standard; these are often forgotten.
  • Do not send a password to a colleague by chat or email. It is better to create a separate user for them.
  • Delete unused accounts, not just deactivate them.

The username admin gives away half the equation. If you still have it, create a new administrator with another name, move the content to it and delete admin. Also set a "display name" different from the login name, so the username is not shown on posts.

Two-factor authentication#

With two-factor authentication, even if the password leaks, an attacker also needs a one-time code from your phone. The usual method is a time-based code (TOTP) with an authenticator app on your mobile. Choose SMS only when there is no other option; it is weaker from a security standpoint.

General steps:

  1. From the official WordPress repository, choose a two-factor plugin that is active and up to date.
  2. Install it, enable it for your own account and scan the QR code with an authenticator app.
  3. Save the backup codes right then; if you lose your phone, they are the only thing that rescues you.
  4. Then make it mandatory for the administrator and editor roles.
  5. In a private window, test that login really asks for a code.

If it is a store, customers do not need two-factor authentication; it is essential for everyone who has dashboard access.

Limiting failed attempts#

Ready-made plugins do this, but the logic is simple and can be done with a few lines of code. The code below locks an IP address for 15 minutes after five failed logins from it. The counter is stored in a transient and expires by itself. Put it in a small plugin or an mu-plugin.

PHP
<?php
function di9_login_key(): string {
	$ip = isset( $_SERVER['REMOTE_ADDR'] )
		? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) )
		: 'unknown';
	return 'di9_fail_' . md5( $ip );
}

add_filter( 'authenticate', function ( $user ) {
	if ( (int) get_transient( di9_login_key() ) >= 5 ) {
		return new WP_Error(
			'too_many_attempts',
			esc_html__( 'Too many failed attempts. Please try again in a few minutes.', 'di9' )
		);
	}
	return $user;
}, 30 );

add_action( 'wp_login_failed', function () {
	$key = di9_login_key();
	set_transient( $key, (int) get_transient( $key ) + 1, 15 * MINUTE_IN_SECONDS );
} );

Two notes. If you are behind a proxy or CDN, REMOTE_ADDR is the proxy's IP and all users share one address; in that case use a server-level lock or that service's firewall. Second, this code does not replace a firewall; it only makes mass guessing more expensive.

Reducing the attack surface#

A few small settings that cost nothing:

TaskWhy
Disable file editing from the dashboardAn attacker who gets in cannot directly change theme and plugin code
Block XML-RPC if you do not use itIt is another route for password guessing
Update regularlyMost intrusions come through an outdated plugin
Users with the least access neededAn author should not be an administrator

To disable file editing, add this line in wp-config.php above the "That's all, stop editing" comment:

PHP
define( 'DISALLOW_FILE_EDIT', true );

For XML-RPC, if no mobile app or plugin depends on it, this filter is enough:

PHP
add_filter( 'xmlrpc_enabled', '__return_false' );

Keep in mind that some services (such as certain plugin connections) use XML-RPC or REST; after the change, test all your important connections. For updates, also read safe WordPress updates.

If you see something odd#

An unknown administrator, repeated logins from unrelated places, or a "password reset" email you did not request are all warning signs. Change passwords immediately, review the user list, and if you suspect a break-in, go to cleaning up a hacked WordPress site. And do not forget that a fresh backup is the last line of defense: automatic WordPress backups.

Roles and least privilege#

Many sites make every colleague an "administrator" because it is easier. That convenience gets expensive later: every administrator account is a complete way in. An article writer needs the "Author" role, not administrator. For a contractor who only works for a few days, create a temporary account and delete it when the job is done. Every few months, review the user list and delete unused accounts.

If the site has several authors or is a store, look at what new roles plugins have added and what permissions each role has. A "shop manager" role also has sensitive access and must be protected with the same care.

Login alerts and review#

It is good to know who logged in to the site and when. Several reputable plugins offer activity logs and record logins. Even a notification email for administrator logins is enough to spot an odd pattern early. Hosts usually keep access logs too; if the number of wp-login.php requests suddenly rises, an attack is underway and you should enable a firewall or a server-level lock.

One last note about sessions: on a shared computer or in an internet cafe, do not use "Remember me", and log out when you finish. If you lose a phone or computer, change your password and end all sessions from your WordPress profile.

Summary#

  • A strong password means long and unique; a password manager makes it easy.
  • Enable two-factor authentication (TOTP) for every user with dashboard access and keep the backup codes.
  • Limit failed attempts, with short code, a plugin or a firewall.
  • Delete the admin user and disable file editing from the dashboard.
  • Disable XML-RPC if you do not need it, but test your connections.
  • Changing the login URL is decoration, not security.