---
title: "Harden WordPress Login with a Must-Use Plugin"
description: "A must-use plugin loads before regular plugins and cannot be deactivated from the dashboard, which makes it a good home for small security rules. The snippet below is written defensively and does nothing risky. ## What should a login-hardening snippet…"
url: "https://apatecreative.com/knowledge-base/wp-security/harden-wordpress-login-with-a-must-use-plugin/"
updated: "2026-10-11"
category: WP Security
---

# Harden WordPress Login with a Must-Use Plugin

A must-use plugin loads before regular plugins and cannot be deactivated from the dashboard, which makes it a good home for small security rules. The snippet below is written defensively and does nothing risky.

## What should a login-hardening snippet cover?

At minimum it should stop username discovery through the REST API and author archives, disable XML-RPC if you do not use it, and record failed login attempts. These three changes remove the most common automated probing without needing another large plugin.

## The snippet

```
<?php
/**
 * Plugin Name: Login Hardening (MU)
 * Description: Small, defensive login protections.
 */
if ( ! defined( 'ABSPATH' ) ) { return; }

// Hide the user list from logged-out REST requests.
add_filter( 'rest_endpoints', function ( $endpoints ) {
	if ( ! is_user_logged_in() ) {
		foreach ( array_keys( $endpoints ) as $route ) {
			if ( 0 === strpos( $route, '/wp/v2/users' ) ) { unset( $endpoints[ $route ] ); }
		}
	}
	return $endpoints;
} );

// Disable XML-RPC.
add_filter( 'xmlrpc_enabled', '__return_false' );

// Log failed logins to debug.log.
add_action( 'wp_login_failed', function ( $username ) {
	error_log( '[login-failed] ' . sanitize_user( $username ) );
} );
```

## Install it

1. Create the folder `wp-content/mu-plugins/` if it does not exist.
2. Save the snippet as `login-hardening.php` inside it.
3. Load the login page and confirm there are no PHP errors in `debug.log`.

## Roll back

Delete the file. Because it is a single file with no database changes, removing it restores the previous behavior immediately.
