Monitoring WordPress login attempts gives you visibility into successful and failed authentication activity so you can identify repeated password guessing, targeted usernames, unusual access patterns and accounts that may require additional protection.
WordPress already exposes authentication hooks that make this possible without modifying Core files.
The two most useful hooks are:
wp_login_failed
→ fires after an authentication failure
wp_login
→ fires after a successful login
Those events can be recorded in:
- a dedicated database table;
- a security plugin log;
- an external logging platform;
- a controlled application log;
- a dedicated WordPress access-management interface.
Monitoring, however, is only one part of login security.
A log does not automatically:
- stop repeated attempts;
- lock out abusive clients;
- strengthen passwords;
- add two-factor authentication;
- disable compromised accounts.
The useful architecture is:
Monitoring
→ tells you what happened
Rate limiting
→ controls repeated attempts
Two-factor authentication
→ strengthens identity verification
Account controls
→ determine who may log in
Roles and capabilities
→ determine what authenticated users may do
This guide explains how to monitor WordPress login attempts safely, which authentication hooks to use, which information to record, what not to log, how to handle IP addresses and reverse proxies, how to detect useful patterns and how monitoring fits into a broader WordPress login-security strategy.
Why monitor WordPress login attempts?
A WordPress login page exposed to the internet will often receive authentication traffic that has nothing to do with legitimate users.
You may see attempts involving:
admin
administrator
webmaster
companyname
known author names
real user email addresses
or repeated attempts against one privileged account.
Without logging, all of that activity disappears after WordPress returns the login error.
With monitoring, you can begin to answer:
- Which identifiers are being targeted?
- How frequently are failures occurring?
- Are many accounts being attempted from the same source?
- Is one account receiving attempts from many sources?
- Did a successful login follow repeated failures?
- Are dormant accounts suddenly authenticating again?
- Are lockout thresholds being reached?
Monitoring is different from limiting login attempts
These two controls are related but not interchangeable.
Login monitoring
→ records activity
Login limiting
→ changes what happens
after repeated failures
If the objective is to actively slow or stop repeated attempts, see How to Limit Login Attempts in WordPress.
For the complete authentication model, see WordPress Login Security Layers, Explained.
What should a WordPress login log record?
A useful authentication event can contain:
Event type
Timestamp
User or attempted identifier
Source identifier
Authentication result
Relevant error category
For example:
2026-09-22 08:15:21
FAILED
identifier: admin
source: 7c4a...
error: incorrect_password
or:
2026-09-22 08:17:04
SUCCESS
user ID: 42
source: 92ad...
You do not necessarily need to store every value in plaintext.
Never log passwords
This is the most important rule in the guide.
Do not record:
- submitted passwords;
- authentication cookies;
- session tokens;
- two-factor codes;
- password-reset tokens.
A login-monitoring system should never become a new repository of authentication secrets.
Be careful with the wp_authenticate hook
WordPress provides the:
wp_authenticate
action before authentication takes place.
The official wp_authenticate documentation shows that the hook receives:
$user_login
$user_password
The password is therefore available to callbacks attached to this hook.
That makes it a particularly poor place for careless diagnostic logging.
Never do this:
add_action(
'wp_authenticate',
function ( $username, $password ) {
error_log(
$username . ':' . $password
);
},
10,
2
);
That would write submitted credentials into a log file.
Use post-authentication events instead
For ordinary login monitoring, WordPress already provides cleaner events after the result is known:
wp_login_failed
→ failed authentication
wp_login
→ successful authentication
For a deeper explanation of the authentication lifecycle, see WordPress Login Hooks Explained.
Monitor failed WordPress logins with wp_login_failed
WordPress fires:
wp_login_failed
after wp_authenticate() fails.
The hook receives:
$username
$error
where $username can contain the submitted username or email address and $error is a WP_Error object describing the authentication failure.
The official wp_login_failed reference documents this event.
Basic failed-login monitor
A minimal development example could be:
add_action(
'wp_login_failed',
'project_log_failed_login',
10,
2
);
function project_log_failed_login(
$username,
$error
) {
$error_code = '';
if ( $error instanceof WP_Error ) {
$error_code = $error->get_error_code();
}
error_log(
sprintf(
'WordPress login failed: %s [%s]',
sanitize_text_field( $username ),
sanitize_key( $error_code )
)
);
}
This demonstrates the hook, but normal PHP logs are rarely the best long-term security-event store.
Why error_log() is not a complete monitoring system
error_log() can be useful temporarily during development.
For production monitoring it creates several limitations:
- authentication events are mixed with application errors;
- retention may be controlled outside WordPress;
- searching and filtering can be difficult;
- access to the file may not match WordPress permissions;
- log files can grow indefinitely;
- rotation depends on server configuration;
- sensitive identifiers may be written in plaintext.
A dedicated event store is easier to reason about.
Monitor successful WordPress logins with wp_login
WordPress fires:
wp_login
after a successful login.
The official wp_login documentation shows that the callback receives:
$user_login
$user
where $user is the authenticated WP_User object.
Basic successful-login monitor
add_action(
'wp_login',
'project_log_successful_login',
10,
2
);
function project_log_successful_login(
$user_login,
$user
) {
error_log(
sprintf(
'WordPress login success: user %d',
absint( $user->ID )
)
);
}
Notice that the log can use the internal user ID rather than unnecessarily storing additional account information.
Successful logins matter too
Security monitoring should not consist only of failures.
A successful login can be the event that matters most.
For example:
200 failed attempts
↓
one successful login
deserves much more attention than:
two failed attempts
↓
same user succeeds
30 seconds later
The second pattern may simply be a mistyped password.
OWASP recommends monitoring authentication successes and failures
The OWASP Logging Cheat Sheet includes authentication successes and failures among the events that should generally be logged for security monitoring.
The OWASP Authentication Cheat Sheet likewise recommends logging and reviewing authentication failures and account lockouts.
The important word is not merely:
log
but:
log
+
review
A log nobody reviews has limited value
Recording millions of rows without ever inspecting them does not provide much operational benefit.
A monitoring strategy should define:
- which events matter;
- how long they are retained;
- who may view them;
- which patterns trigger investigation;
- which events should create alerts.
Use a dedicated database table for structured monitoring
If you are implementing login monitoring yourself, a dedicated table can keep authentication events separate from WordPress content and options.
A privacy-conscious structure could store:
ID
Event type
User ID
Hashed attempted identifier
Hashed source IP
Error code
Timestamp
This lets you correlate repeated activity without storing every value directly.
Create the table on plugin activation
WordPress provides:
register_activation_hook()
for plugin activation logic.
The official register_activation_hook() documentation covers this lifecycle.
For database schema creation, WordPress provides:
dbDelta()
documented in the official dbDelta() reference.
Example login-monitor table
register_activation_hook(
__FILE__,
'project_login_monitor_activate'
);
function project_login_monitor_activate() {
global $wpdb;
$table_name = $wpdb->prefix
. 'login_events';
$charset_collate =
$wpdb->get_charset_collate();
$sql = "CREATE TABLE {$table_name} (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
event_type varchar(20) NOT NULL,
user_id bigint(20) unsigned DEFAULT NULL,
identifier_hash char(64) NOT NULL,
ip_hash char(64) DEFAULT NULL,
error_code varchar(100) DEFAULT NULL,
created_at datetime NOT NULL,
PRIMARY KEY (id),
KEY event_type (event_type),
KEY user_id (user_id),
KEY identifier_hash (identifier_hash),
KEY ip_hash (ip_hash),
KEY created_at (created_at)
) {$charset_collate};";
require_once ABSPATH
. 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
}
Why hash attempted identifiers?
A failed login can contain:
username
or
email address
depending on what was submitted.
If the monitoring requirement is primarily:
Are the same identifiers
being targeted repeatedly?
you may not need to store the original value.
A keyed hash can allow repeated identifiers to produce the same stored value without keeping the attempted identifier directly readable.
Example keyed hashing helper
function project_login_monitor_hash(
$value
) {
$value = strtolower(
trim(
(string) $value
)
);
if ( '' === $value ) {
return '';
}
return hash_hmac(
'sha256',
$value,
wp_salt( 'auth' )
);
}
This reduces the amount of directly readable information stored in the event table.
Hashing is not the same as making data anonymous
A deterministic hash can still be useful for correlating activity.
That same characteristic means it should not automatically be described as anonymous data.
Treat security logs as potentially sensitive operational data and apply appropriate:
- access control;
- retention;
- documentation;
- data-minimization decisions.
Do you need to store IP addresses?
An IP address can help answer questions such as:
Are many accounts being
attempted from one source?
Does the same source repeatedly
fail against one account?
Did a successful login follow
failures from the same source?
However, storing IP addresses also increases the amount of user-related data retained by the website.
Decide whether you need:
raw IP
hashed IP
short-lived IP
or
no IP at all
according to your actual monitoring requirements and applicable privacy obligations.
A hashed IP can still support correlation
For example:
192.0.2.20
↓
HMAC
↓
3b8818...
You can still detect:
same source hash
appeared 53 times
without displaying the original address in the WordPress interface.
Retrieve the immediate remote address carefully
A conservative helper can read:
REMOTE_ADDR
and validate it as an IP address.
function project_login_monitor_ip() {
if (
empty(
$_SERVER['REMOTE_ADDR']
)
) {
return '';
}
$ip = wp_unslash(
$_SERVER['REMOTE_ADDR']
);
if (
false === filter_var(
$ip,
FILTER_VALIDATE_IP
)
) {
return '';
}
return $ip;
}
Reverse proxies make IP monitoring more complicated
A website may sit behind:
- Cloudflare;
- a reverse proxy;
- a load balancer;
- a hosting edge network;
- another security gateway.
In those environments, REMOTE_ADDR may represent the proxy rather than the original visitor.
Do not blindly trust X-Forwarded-For
A common mistake is replacing:
REMOTE_ADDR
with:
X-Forwarded-For
without validating the network architecture.
A client can potentially send forwarding headers itself unless the trusted proxy layer overwrites and validates them.
Configure the server or trusted proxy correctly before treating forwarded headers as authoritative security data.
TheOneWP Access Manager uses REMOTE_ADDR
TheOneWP Access Manager currently uses REMOTE_ADDR for its IP-oriented access controls and authentication-event monitoring.
On sites behind a proxy, CDN or load balancer, verify which address WordPress actually receives before relying on IP-based rules.
Record the event without storing credentials
A shared event-insertion function can look like:
function project_login_monitor_insert(
$event_type,
$user_id,
$identifier,
$error_code = ''
) {
global $wpdb;
$table_name = $wpdb->prefix
. 'login_events';
$ip = project_login_monitor_ip();
$wpdb->insert(
$table_name,
array(
'event_type' =>
sanitize_key(
$event_type
),
'user_id' =>
$user_id
? absint( $user_id )
: null,
'identifier_hash' =>
project_login_monitor_hash(
$identifier
),
'ip_hash' =>
$ip
? project_login_monitor_hash(
$ip
)
: null,
'error_code' =>
$error_code
? sanitize_key(
$error_code
)
: null,
'created_at' =>
current_time(
'mysql',
true
),
),
array(
'%s',
'%d',
'%s',
'%s',
'%s',
'%s',
)
);
}
The official wpdb::insert() reference documents structured row insertion.
The timestamp uses WordPress’s:
current_time()
function, documented by the official current_time() reference.
Connect the logger to failed attempts
add_action(
'wp_login_failed',
'project_login_monitor_failed',
10,
2
);
function project_login_monitor_failed(
$username,
$error
) {
$error_code = '';
if ( $error instanceof WP_Error ) {
$error_code =
$error->get_error_code();
}
project_login_monitor_insert(
'failed',
null,
$username,
$error_code
);
}
Connect the logger to successful logins
add_action(
'wp_login',
'project_login_monitor_success',
10,
2
);
function project_login_monitor_success(
$user_login,
$user
) {
project_login_monitor_insert(
'success',
$user->ID,
$user_login
);
}
Now both result types enter the same structured event table.
Do not store the submitted password anywhere in this flow
The event functions only need:
result
identifier
user ID when available
source correlation
error category
timestamp
The password is not required for security-event analysis.
Authentication error codes can provide useful context
The failure hook receives a WP_Error object.
Different authentication failures may therefore provide different codes.
Store the code rather than copying a full human-readable login error message into your database.
This produces cleaner structured data and avoids unnecessary text.
For the relationship between WordPress login errors and account information, see WordPress Login Error Messages Explained.
Do not expose detailed monitoring data publicly
A login-event log belongs in an authenticated administrative context or external protected monitoring system.
Do not create:
/login-events.json
as a publicly accessible endpoint containing:
- usernames;
- email addresses;
- IP addresses;
- login timestamps;
- failure patterns.
Protect any custom log viewer with capabilities
If you create an administration page for login events, protect it using a suitable capability such as:
manage_options
or a dedicated custom capability.
Do not rely only on hiding the menu item.
Permission checks must protect the page callback and any related AJAX or REST actions.
Use WordPress security APIs normally
The official WordPress Security documentation recommends validating input and escaping output according to context.
A login-log interface should follow the same rules as any other WordPress administration feature.
Retain login logs for a defined period
Authentication logs should not necessarily exist forever.
Choose a retention period according to:
- security requirements;
- incident-response needs;
- site traffic;
- storage constraints;
- privacy policy;
- organizational obligations.
For one site, 30 days may be enough.
Another organization may require a longer documented retention period.
The important point is to make the policy intentional.
Automatically prune old events
WordPress provides:
wp_schedule_event()
for recurring WP-Cron events.
The official wp_schedule_event() documentation covers recurring scheduling.
Schedule daily cleanup on activation
register_activation_hook(
__FILE__,
'project_login_monitor_schedule'
);
function project_login_monitor_schedule() {
if (
! wp_next_scheduled(
'project_login_monitor_prune'
)
) {
wp_schedule_event(
time() + HOUR_IN_SECONDS,
'daily',
'project_login_monitor_prune'
);
}
}
Delete events older than 30 days
add_action(
'project_login_monitor_prune',
'project_login_monitor_prune_events'
);
function project_login_monitor_prune_events() {
global $wpdb;
$table_name = $wpdb->prefix
. 'login_events';
$cutoff = gmdate(
'Y-m-d H:i:s',
time() - ( 30 * DAY_IN_SECONDS )
);
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$table_name}
WHERE created_at < %s",
$cutoff
)
);
}
Clear the scheduled event when the plugin is deactivated
register_deactivation_hook(
__FILE__,
'project_login_monitor_deactivate'
);
function project_login_monitor_deactivate() {
wp_clear_scheduled_hook(
'project_login_monitor_prune'
);
}
Do not leave unnecessary scheduled tasks behind when the monitoring plugin is no longer active.
WP-Cron is not a real-time security scheduler
WordPress WP-Cron is request-driven by default.
That is generally acceptable for routine log cleanup.
Do not depend on it for precise real-time incident detection unless your environment provides an appropriate scheduler architecture.
What patterns should you look for?
The value of login monitoring comes from patterns rather than isolated rows.
Many failures against one identifier
identifier hash A
↓
failure
failure
failure
failure
failure
This may indicate targeted password guessing against one account.
Many identifiers from one source
source hash X
↓
admin
john
sales
editor
support
jane@example.com
This can indicate automated credential testing or account discovery.
One identifier from many sources
administrator
↓
source A
source B
source C
source D
This may indicate a distributed attempt against a known or guessed privileged identifier.
Repeated failures followed by a success
FAILED
FAILED
FAILED
FAILED
SUCCESS
This deserves context.
It might be:
- a legitimate user remembering the correct password;
- an administrator entering old credentials;
- a successful credential attack.
The log alone does not prove which explanation is correct.
Do not label every failed login an attack
Real users mistype passwords.
Password managers contain old credentials.
Integrations can continue using outdated passwords.
Mobile applications can retry failed authentication automatically.
Monitoring should help distinguish patterns, not create panic around every error.
Rate matters
These patterns are very different:
3 failures
over 8 hours
and:
300 failures
in 60 seconds
Count, frequency and distribution should be considered together.
Monitor targeted account names
If the same identifiers repeatedly appear in failed authentication activity, investigate how those identifiers may have become predictable or public.
This is particularly relevant for:
- administrator usernames;
- public author names;
- email-based logins;
- company-standard account naming.
For the tradeoffs between username and email authentication, see WordPress Login: Username vs. Email, Which Is More Secure?.
Restricting allowed identifiers is a separate control
TheOneWP Restrict Login Identifier controls which identifier types WordPress accepts during authentication.
That changes login behavior.
Monitoring only observes what happens.
Last Login is different from login-attempt monitoring
A Last Login field answers:
When did this account
last authenticate successfully?
It does not answer:
How many failed attempts
targeted this account?
TheOneWP Last Login records successful authentication activity and exposes the latest login information for users.
Use both data types when they solve different questions.
Last Login is useful for dormant-account reviews
If an account has not successfully logged in for a long time, it may deserve review.
That process is covered in Auditing Dormant WordPress User Accounts.
Monitoring can reveal accounts that should no longer exist
Suppose your log shows repeated attempts against:
old-contractor
and the user still exists with administrative privileges.
The problem is no longer merely:
failed authentication traffic
It is also:
Why does this account
still have access?
See How to Audit User Roles on a WordPress Site.
Block accounts when access should be suspended
If a user record must remain for content ownership or auditing but should no longer authenticate, deleting it is not the only option.
TheOneWP Block User Login provides a separate control for suspending authentication while retaining the user record.
Two-factor authentication changes the risk after password compromise
Monitoring may reveal that a privileged account is receiving repeated targeted attempts.
That is a strong reason to verify whether the account has stronger authentication controls.
TheOneWP Two-Factor Authentication adds another factor to supported authentication flows.
Monitoring tells you:
someone is attempting access
while 2FA changes:
what is required
for successful access
Monitoring should complement rate limiting
Repeated failures should not merely create more database rows forever.
At some point, an access-control layer may need to respond.
TheOneWP Access Manager combines login-attempt controls, IP rules, lockout behavior and a centralized authentication-event log.
Its current implementation keeps the authentication log capped rather than allowing unrestricted growth and stores IP values as salted SHA-256 hashes.
TheOneWP Access Manager and reverse proxies
The current Access Manager implementation deliberately uses:
REMOTE_ADDR
rather than automatically trusting forwarded headers.
Therefore, when the website sits behind:
- a CDN;
- reverse proxy;
- load balancer;
verify that the server environment exposes the intended visitor address through REMOTE_ADDR.
Otherwise multiple visitors may appear to originate from the same proxy address.
Monitoring does not replace two-factor authentication
A site with excellent logs but weak authentication can still be compromised.
A stronger model is:
Strong password
+
2FA
+
rate limiting
+
monitoring
+
account review
For a structured implementation review, see A WordPress Login Hardening Checklist.
Changing the login URL is another separate layer
Some sites change:
/wp-login.php
to a custom location.
This can reduce automated traffic against the default URL, but it does not replace monitoring.
See How to Change the WordPress Login URL.
Do not treat a hidden login URL as complete protection
A custom login URL is a traffic-management and obscurity layer, not a substitute for authentication security.
See Does Hiding wp-login.php Actually Help Security?.
Login feedback should remain separate from monitoring
A login form may need to explain:
- invalid credentials;
- blocked accounts;
- lockouts;
- 2FA requirements;
- other authentication states.
That interface feedback is different from the private monitoring log.
TheOneWP Login Toast Notifications addresses the user-facing notification layer rather than security-event storage.
Do not expose your internal monitoring logic through login errors
The public login form does not need to display:
This account has received
47 failed attempts from
12 different IP addresses.
That information belongs in the administrative monitoring system.
WordPress authentication may happen outside wp-login.php
Not every authentication flow necessarily originates from the visible WordPress login form.
Core authentication functions can also be used by other WordPress flows.
The official wp_authenticate() reference shows that successful authentication returns a WP_User and failure returns WP_Error.
The official wp_signon() documentation shows how normal sign-on ultimately fires the wp_login event after the authentication cookie is set.
Custom authentication systems may behave differently
A plugin can introduce:
- single sign-on;
- OAuth;
- external identity providers;
- custom authentication endpoints;
- headless login flows.
Do not assume every authentication system on a complex WordPress installation passes through exactly the same hooks.
Test the actual site’s authentication paths.
Two-factor plugins may change the timing
Some 2FA implementations intercept or extend the normal WordPress authentication lifecycle.
Verify whether:
wp_login
represents:
password accepted
or:
complete authentication flow accepted
for the particular 2FA system installed.
Do not infer plugin behavior without testing it.
Application logs and web-server logs answer different questions
A WordPress login monitor sees application-level authentication events.
A web-server or edge log can also record:
- requests that never reach WordPress;
- blocked requests;
- HTTP status codes;
- request rates;
- paths;
- network-level information.
These sources complement each other.
WordPress monitoring is not a replacement for server security logs
Consider:
web server / WAF
→ request visibility
WordPress login logger
→ authentication result
application audit log
→ user actions after login
Each layer answers a different question.
Do not log complete HTTP requests by default
A login POST request can contain credentials.
Do not dump:
$_POST
$_REQUEST
request body
into logs during authentication debugging.
You risk storing:
- passwords;
- 2FA tokens;
- redirect parameters;
- other sensitive data.
Do not log authentication cookies
WordPress sets authentication cookies after successful login.
The official wp_set_auth_cookie() documentation shows that those cookies are directly connected to authenticated sessions.
Never store cookie values merely to make the login log “more complete.”
Session monitoring is another separate layer
WordPress manages user sessions through:
WP_Session_Tokens
The official WP_Session_Tokens reference covers session-token management.
A login event tells you authentication occurred.
A session system tells you which authenticated sessions remain valid.
Do not confuse the two.
Successful login does not tell you everything the user did afterward
A login monitor can tell you:
User 42 authenticated
at 09:20 UTC
It cannot automatically tell you:
User 42 changed plugin settings
deleted a page
installed a plugin
exported user data
Those require broader activity or audit logging.
Define alert thresholds carefully
If you send an alert for every failed login, a public WordPress site can become noisy very quickly.
More useful triggers may include:
- a large burst of failures;
- many failures against a privileged account;
- success after an unusual failure pattern;
- a blocked account attempting authentication;
- activity involving a dormant administrator;
- repeated lockouts.
Avoid alert fatigue
A monitoring system that sends hundreds of low-value notifications encourages administrators to stop reading them.
OWASP’s logging guidance emphasizes defining security logging according to actual risk rather than collecting everything without purpose.
Do not automatically blacklist every failed source
One failed login is not sufficient evidence that a source is malicious.
Users:
- mistype passwords;
- use stale saved credentials;
- change networks;
- share office gateways;
- sit behind carrier-grade NAT.
Automatic enforcement should use a defined threshold and recovery strategy.
IP addresses are not user identities
One IP address can represent:
- an office;
- a household;
- a mobile carrier;
- a VPN exit;
- a proxy;
- a CDN;
- a shared hosting gateway.
Likewise, one user can appear from many addresses over time.
Use IP data as one signal, not as unquestionable proof of identity.
Usernames are not identities either
A failed attempt against:
admin
does not prove that a user named admin actually exists.
The attacker may simply be guessing common identifiers.
Do not enrich failed-login logs with unnecessary account-existence information unless the monitoring requirement genuinely needs it.
Avoid turning the monitoring database into a username enumeration source
If a log viewer explicitly labels every attempted identifier as:
VALID USER
or
INVALID USER
you are creating additional sensitive account metadata.
Record what is necessary for administration, not everything technically derivable.
Audit who can see the login logs
A login-event log may reveal:
- which accounts are privileged;
- when users work;
- which identifiers attackers target;
- source-network patterns;
- security-control behavior.
Not every WordPress editor needs that information.
Restrict access to appropriate administrators or security personnel.
Review logs after account changes
Monitoring becomes especially useful after:
- an employee leaves;
- an agency handover;
- a password reset;
- a suspected compromise;
- 2FA deployment;
- a new login URL;
- a rate-limit policy change.
Those events create useful points for comparison.
Review the logs after enabling rate limits
If a rate-limiting system is introduced, check whether:
- automated attempts decline;
- legitimate users are being locked out;
- one source simply rotates between addresses;
- privileged accounts remain heavily targeted.
Monitoring helps validate whether the security control behaves as expected.
Review logs after enabling 2FA
Two-factor authentication changes the authentication flow but does not necessarily eliminate password attempts.
You may continue to see:
failed primary authentication
even after 2FA is enabled.
The difference is that a valid password alone is no longer necessarily sufficient.
Monitor privileged accounts more carefully
Accounts with capabilities such as:
manage_options
install_plugins
edit_users
delete_users
carry greater potential impact if compromised.
A burst of failures against a Subscriber is not necessarily equivalent in operational importance to the same pattern against an Administrator.
Monitoring and role auditing belong together
Authentication risk depends partly on what happens after a successful login.
An account with excessive privileges increases the impact of credential compromise.
This is why user-role auditing belongs in the same security program even though it is not part of the login logger itself.
Do not keep dormant administrator accounts indefinitely
A login log can reveal accounts that have not authenticated for months or years.
Review whether those accounts still need:
- login access;
- administrator privileges;
- any account at all.
Use Last Login and Auditing Dormant WordPress User Accounts as complementary tools.
Test your monitoring implementation
Do not wait for real attack traffic before discovering the logger does not work.
Create a controlled test plan.
Test one failed login
Use a dedicated test account and intentionally enter an incorrect password once.
Confirm:
failed event exists
timestamp is correct
identifier correlation exists
error code is recorded
source correlation exists
Test one successful login
Authenticate normally with the test account.
Confirm:
success event exists
user ID is correct
timestamp is correct
Test multiple failures
Perform several controlled failures and verify that they can be grouped by:
- identifier;
- source;
- time window.
Test retention
Insert an intentionally old test record or reduce the temporary retention window in a development environment.
Confirm that pruning removes the expected rows.
Test proxy behavior
If the production site uses a CDN or proxy, verify the source value in that actual architecture.
Do not assume local development reproduces it.
Test without risking a real lockout
If monitoring is combined with attempt limiting, use:
- a test account;
- a known recovery path;
- conservative thresholds;
- a recoverable test IP.
Do not experiment with aggressive lockout rules using the only administrator account on a production website.
Monitoring WordPress Multisite
Multisite introduces an additional question:
Is the event relevant to
one site
or
the network?
User accounts can span multiple sites while authentication occurs against the shared installation.
Decide whether the event table should include:
blog_id
network_id
or
installation-wide context
according to the monitoring architecture.
Do not assume one-site reporting works unchanged on Multisite
Test:
- site administrators;
- Super Admins;
- Network Admin;
- users assigned to multiple sites.
Monitoring and privacy need a deliberate policy
Security monitoring creates operational data about authentication behavior.
Before storing:
- IP addresses;
- email addresses;
- usernames;
- user agents;
- timestamps;
ask whether each field is actually required.
The OWASP logging guidance likewise recommends considering the value of logged fields against the responsibility created by retaining them.
Data minimization improves security too
If an event database is exposed, information you never stored cannot be leaked from it.
A useful principle is:
store enough
to investigate
not everything
available in the request
A practical minimal login event
For many installations, this is enough:
event type
user ID when known
hashed identifier
hashed source
error code
UTC timestamp
You may not need:
full request body
password
cookie
browser fingerprint
complete HTTP headers
full user profile
Use UTC for security-event timestamps
Security events are easier to compare across systems when they use one consistent timezone.
The example logger stores:
current_time(
'mysql',
true
)
which returns a GMT/UTC-based WordPress time value.
You can convert timestamps for human display later.
Do not store only formatted local time
Local time introduces complications around:
- daylight-saving changes;
- timezone configuration changes;
- comparison with server logs;
- comparison with CDN logs.
Consistent UTC timestamps simplify correlation.
Monitoring should have a clear response plan
If you discover a suspicious pattern, know what happens next.
Possible responses include:
- review the targeted account;
- reset compromised credentials;
- enable or enforce 2FA;
- reduce excessive privileges;
- block a user account;
- adjust rate limits;
- review server or WAF logs;
- terminate suspicious sessions;
- investigate recent administrative changes.
Do not automatically reset every targeted password
Failed attempts against a username do not mean the password was compromised.
Respond according to evidence.
A username being guessed is very different from a successful login from an unexplained context.
A successful suspicious login deserves broader investigation
If an account appears compromised, monitoring should expand beyond the authentication event.
Review:
- current sessions;
- user-role changes;
- plugin installations;
- new administrator accounts;
- site configuration changes;
- modified content;
- server and edge logs.
Login logs are one source of evidence
Do not assume:
no suspicious login event
=
no compromise
An attacker may exploit another vulnerability without authenticating through the normal login flow.
TheOneWP monitoring workflow
TheOneWP separates authentication responsibilities into focused modules.
Access Manager provides failed-attempt controls, IP access rules, lockouts and authentication-event visibility.
Last Login records successful authentication context for individual users.
Two-Factor Authentication strengthens accounts that need additional identity verification.
Block User Login can suspend authentication for a user without deleting the account.
Restrict Login Identifier controls which identifier types may be used during authentication.
Those responsibilities should remain conceptually separate:
Access Manager
→ attempts, IP rules,
lockouts and event visibility
Last Login
→ latest successful access
Two-Factor Authentication
→ stronger authentication
Block User Login
→ suspend account access
Restrict Login Identifier
→ accepted login identity type
Common mistake: logging passwords
Never store submitted authentication secrets.
A security logger that captures passwords creates a more serious security problem than the one it was intended to investigate.
Common mistake: dumping $_POST into the log
The WordPress login request contains the submitted password.
Do not log the entire request payload.
Common mistake: monitoring failures but not successes
A successful authentication following repeated failures can be more significant than the failures themselves.
Record both result types.
Common mistake: storing logs forever
Define a retention policy and enforce it.
Unlimited event storage creates unnecessary database growth and additional data exposure.
Common mistake: using raw IP addresses when you only need correlation
If the requirement is merely to identify repeated activity from the same source, a keyed hash may provide sufficient correlation with less directly readable network data.
Common mistake: claiming hashed IPs are completely anonymous
Pseudonymization and anonymization are not automatically the same thing.
Treat security-event data carefully even when identifiers are hashed.
Common mistake: trusting X-Forwarded-For automatically
Only trust forwarded IP information when it is supplied and validated by infrastructure you control.
Common mistake: treating an IP as one person
Shared networks, mobile carriers, VPNs and proxies break that assumption.
Common mistake: using monitoring as the only login protection
A database containing perfect evidence of thousands of guesses is not a rate limiter.
Combine visibility with actual controls.
Common mistake: treating a custom login URL as monitoring
Changing the endpoint can reduce some automated traffic.
It does not tell you what authentication activity actually occurred.
Common mistake: assuming wp_login_failed captures every possible authentication system
Custom SSO or authentication plugins can alter the flow.
Test the technologies installed on the actual website.
Common mistake: mixing authentication logs with general PHP errors
A dedicated store provides cleaner retention, filtering and permission boundaries.
Common mistake: exposing logs to ordinary editors
Authentication-event data should be available only to users with a legitimate administrative or security need.
Common mistake: alerting on every typo
Design thresholds around patterns and risk rather than individual mistakes.
Common mistake: ignoring dormant accounts
Monitoring is more valuable when combined with periodic account review.
An old administrator account receiving fresh login attempts deserves investigation even if every attempt fails.
Production checklist
- Record both successful and failed authentication events.
- Use
wp_login_failedfor normal failed WordPress authentication monitoring. - Use
wp_loginfor successful login monitoring. - Never log passwords.
- Never log authentication cookies or session tokens.
- Do not dump full login POST requests into logs.
- Store only the fields required for investigation.
- Consider hashing attempted identifiers when plaintext is unnecessary.
- Consider hashing source IP values when correlation is sufficient.
- Do not automatically describe hashed identifiers as anonymous.
- Validate IP addresses before using them.
- Do not blindly trust forwarded headers.
- Verify proxy and CDN behavior in the production environment.
- Use UTC or another consistent timestamp strategy.
- Keep authentication events in a dedicated store where practical.
- Use WordPress database APIs rather than concatenating untrusted SQL values.
- Define a log-retention period.
- Automatically prune old records.
- Restrict log visibility to appropriate administrators.
- Test one controlled failed login.
- Test one successful login.
- Test repeated failures.
- Test rate-limiting interaction.
- Test two-factor authentication flows.
- Test SSO or custom authentication flows separately.
- Test Multisite separately where applicable.
- Review failures against privileged accounts.
- Review successes following unusual failure patterns.
- Review dormant accounts that suddenly authenticate.
- Combine monitoring with rate limiting.
- Use two-factor authentication for sensitive accounts where appropriate.
- Maintain a response procedure for suspicious successful logins.
- Compare WordPress events with server or edge logs during investigations.
- Do not treat login monitoring as a complete security solution.
Related guides
- How to Limit Login Attempts in WordPress
- WordPress Login Security Layers, Explained
- A WordPress Login Hardening Checklist
- WordPress Login Hooks Explained
- WordPress Login Error Messages Explained
- Auditing Dormant WordPress User Accounts
Final recommendation
WordPress login monitoring should be designed as a security-event system, not as a collection of debug statements.
Use the WordPress authentication lifecycle to record the events that matter:
wp_login_failed
→ authentication failure
wp_login
→ authentication success
A useful minimal event contains:
result
user ID when available
identifier correlation
source correlation
error category
timestamp
It does not need the submitted password, authentication cookie, session token or complete request body.
Store only enough information to identify meaningful patterns, protect access to the log and delete events when they are no longer required.
Then review the data in context.
One failed login may be a typing mistake. Hundreds of failures in seconds are different. A successful login after a long sequence of targeted failures deserves more attention still.
Finally, remember that monitoring provides visibility rather than prevention.
The strongest setup combines:
login monitoring
+
rate limiting
+
strong unique passwords
+
two-factor authentication
+
account auditing
+
least privilege
+
a defined incident response process
TheOneWP Access Manager provides the attempt-management and authentication-event layer, while Last Login, Two-Factor Authentication and Block User Login address separate parts of the wider WordPress account-security workflow.

