1. Incident scenario and blocking hypotheses#
If the login page (wp-login.php) doesn't even load, your investigation must focus on the following request blocking layers:
- Web Server or WAF: HTTP
403 Forbiddenerrors generated by ModSecurity (Apache) or strict directives in Nginx. - Security Plugin: A block triggered during the WordPress bootstrap by an unstable or overactive security plugin.
- Rules in
.htaccess: IP blocks/rewrite rules applied by security plugins that persist even after deactivation. - Proxy/CDN Headers: Incorrect client IP detection behind Cloudflare or a reverse proxy.
2. Preventive backups: mandatory P0 step#
Never initiate corrective actions directly in production without first securing backups of your database, plugin files, and server configuration files.
# 1. Full Database backup via WP-CLI
wp db export backup-pre-fix-$(date +%Y%m%d-%H%M%S).sql
# 2. Backup of the content directory (wp-content)
tar czf /tmp/wp-content-backup-$(date +%Y%m%d).tar.gz wp-content/
# 3. Backup of the web server configuration file
cp .htaccess .htaccess.bak.$(date +%F-%H%M%S)
3. Layered diagnosis and log tracing#
3.1 HTTP request test with cURL#
Validate the server's response isolating your local browser session (to bypass local caches):
curl -I https://domain.com/wp-admin/
- HTTP 403 Forbidden: The block is occurring at the web server layer (Apache/Nginx/WAF).
- HTTP 200 OK with a blocking message: The web server allowed the request, but the PHP/WordPress script intercepted and aborted execution.
3.2 temporary debug activation and log tracing#
If the error is generated by WordPress, the bootstrap details will be written to the error log. Temporarily add the following to your wp-config.php:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
After adding it, force-reload the page and inspect the relevant log files:
# 1. WordPress debug log
tail -n 50 wp-content/debug.log
# 2. PHP error log (example path on Debian/Ubuntu)
tail -n 50 /var/log/php/error.log
# 3. Web Server error logs
tail -n 50 /var/log/apache2/error.log
tail -n 50 /var/log/nginx/error.log
4. Host files and permissions audit#
4.1 WordPress file and directory permissions#
Incorrect permissions can prevent Apache or Nginx from reading vital application files, simulating a login lockout. Enforce the security standard:
# Set permissions for directories (755) and files (644)
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;
# Hardening for the sensitive configuration file
chmod 400 wp-config.php
# Grant ownership to the user running the web server
chown -R www-data:www-data /var/www/html
4.2 inspecting .htaccess integrity#
If you run Apache, orphaned or duplicate rewrite rules can block admin access.
# Verify the complete content
cat .htaccess
# Search for security block markings
grep -n "BEGIN\|END" .htaccess
# Check the count of BEGIN blocks
grep -c "BEGIN" .htaccess
If duplicate security blocks or repeated rules are present, clean the file and regenerate the basic WordPress permalinks.
5. Access Recovery: Admin Provisioning and Secure Password Resets via WP-CLI and MySQL#
If the WordPress core is installed and functional (wp core is-installed), we can use the CLI to manage plugins.
5.1 deactivating specific plugins#
Identify the active security plugin and deactivate it using its technical slug:
# List active plugins
wp plugin list --status=active
# Deactivate the problematic plugin
wp plugin deactivate all-in-one-wp-security-and-firewall
If the plugin crashes the WP-CLI bootstrap itself, bypass plugin loading with the --skip-plugins flag:
wp plugin deactivate all-in-one-wp-security-and-firewall --skip-plugins
5.2 global deactivation (emergency)#
If you do not know which plugin caused the lockout, deactivate all active plugins at once:
# Deactivate all active plugins in one command
wp plugin deactivate $(wp plugin list --status=active --field=name) --skip-plugins
# Or using the direct all flag
wp plugin deactivate --all --skip-plugins
Slugs of other common security plugins:#
- Wordfence Security:
wordfence - Solid Security (formerly iThemes):
ithemes-security - Sucuri Security:
sucuri-scanner - BulletProof Security:
bulletproof-security - Shield Security:
wp-security-shield
If you are locked out of WordPress, this guide covers both production-safe recovery paths:
- create a new administrator account;
- reset password for an existing account.
WordPress uses different user roles, each with specific permissions:
- User: can only read and edit their own profile.
- Manager: inherits user permissions and can read/edit posts.
- Collaborator: inherits user permissions and can submit posts.
- Administrator: has full system permissions.
Warning: Permissions may vary depending on your installation and plugins.
Emergency Admin User Creation via WP-CLI#
Via wp-cli#
If WP-CLI is available, creating an administrator is straightforward.
Installation guide:
<https://domain.com/article/instalando-wpcli-na-hospedagem/>
Create a new administrator:
php wp user create USERNAME EMAIL --role=administrator --user_pass="PASSWORD"
Verify creation:
php wp user list
Direct Database Provisioning (Fallback without WP-CLI)#
If WP-CLI is not available, create the admin user directly in the database.
Identify the database used by WordPress:
grep DB wp-config.php
Connect to MySQL/MariaDB:
mysql -u USER -p
If login succeeds, you should see:
MariaDB [(none)]:
Select the database:
use DATABASE_NAME;
List tables to identify the prefix:
show tables;
Sample output:
| wp_e_events |
| wp_e_submissions |
| wp_expm_maker_pages |
| wp_ezoic_endpoints |
In this case, prefix is wp_.
Create the new admin user:
INSERT INTO wp_users (user_login, user_pass, user_nicename, user_email, user_status, display_name)
VALUES ('USERNAME', MD5('USER_PASSWORD'), 'FULL NAME', 'USER_EMAIL', 0, 'FULL NAME');
- USERNAME: e.g.
john - USER_PASSWORD: use a strong password
- FULL NAME: first and last name
- USER_EMAIL: valid email address
Practical example:
INSERT INTO wp_users (user_login, user_pass, user_nicename, user_email, user_status, display_name)
VALUES ('usuario', MD5('mudar123'), 'Usuario Teste', '[email protected]', 0, 'Usuario Teste');
Query OK, 1 row affected (0.001 sec)
Check assigned ID:
SELECT ID FROM wp_users WHERE user_login = 'USERNAME';
Expected output:
SELECT ID FROM wp_users WHERE user_login = 'usuario';
+----+
| id |
+----+
| 90 |
+----+
1 row in set (0.001 sec)
Warning: ID changes for every new user. In the example above, ID is 90.
Grant administrator capabilities:
INSERT INTO wp_usermeta (user_id, meta_key, meta_value)
VALUES (USER_ID, 'wp_capabilities', 'a:1:{s:13:"administrator";b:1;}');
Example:
INSERT INTO wp_usermeta (user_id, meta_key, meta_value)
VALUES (90, 'wp_capabilities', 'a:1:{s:13:"administrator";b:1;}');
Query OK, 1 row affected (0.004 sec)
Also add user level:
INSERT INTO wp_usermeta (user_id, meta_key, meta_value)
VALUES (USER_ID, 'wp_user_level', '10');
Example:
INSERT INTO wp_usermeta (user_id, meta_key, meta_value)
VALUES (90, 'wp_user_level', '10');
Query OK, 1 row affected (0.001 sec)
Done. The user now has administrator permissions and can log in to wp-admin.
Secure Password Reset Procedures (WP-CLI and MySQL)#
If the account already exists, password reset is usually faster than creating a new admin.
With wp-cli#
php wp user list
php wp user update USER_ID --user_pass="NEW_STRONG_PASSWORD"
Emergency database reset#
UPDATE wp_users
SET user_pass = MD5('newPassword123')
WHERE user_login = 'username';
Important: after regaining access, change the password again in WordPress admin so the platform stores a modern password hash.
6. Manual web server contingencies#
If the database or WP-CLI is completely inaccessible, use these filesystem fallbacks directly in the terminal:
6.1 move the physical plugin directory#
Renaming the folder forces WordPress to skip the plugin during bootstrap:
mv wp-content/plugins/all-in-one-wp-security-and-firewall \
wp-content/plugins/all-in-one-wp-security-and-firewall.bak
6.2 temporarily disable ModSecurity (Apache WAF)#
If ModSecurity is active and triggering false positives on /wp-admin/, you can check its status and temporarily disable it:
# Verify if the module is loaded in Apache
apache2ctl -M 2>/dev/null | grep security
# ModSecurity audit logs
tail -n 50 /var/log/apache2/modsec_audit.log
If necessary, disable it via .htaccess for a quick test:
<IfModule mod_security.c>
SecRuleEngine Off
</IfModule>
6.3 validate Nginx settings and logs#
If the stack runs Nginx, check static blocking rules in the configuration:
# Test Nginx configurations syntax integrity
nginx -t
# Search for deny directives or 403 returns
grep -rn "deny\|return 403" /etc/nginx/
# Consult access logs for HTTP 403 errors
tail -n 50 /var/log/nginx/access.log | grep 403
7. Proxy/cdn headers: incorrect source IP#
In server configurations behind proxies or CDNs like Cloudflare, security plugins might read the reverse proxy IP instead of the client IP. If the proxy fails to authenticate or triggers a threshold, the plugin will block the proxy's IP, effectively locking out all site administrators.
Ensure headers such as X-Forwarded-For or CF-Connecting-IP are correctly configured to pass the client's real IP into the WAF settings.
8. Post-fix verification and rollback#
8.1 validating restored access#
Ensure that the REST API and critical admin endpoints are responding properly:
# Test HTTP access to the admin area (expected redirect or form)
curl -I https://domain.com/wp-admin/
# Test direct HTTP access to the login form
curl -I https://domain.com/wp-login.php
# Test REST API integrity
curl -I https://domain.com/wp-json/
8.2 safe rollback runbook#
If deactivating the plugin breaks application functionality or if you need to revert the configurations:
# 1. Reactivate the deactivated plugin
wp plugin activate all-in-one-wp-security-and-firewall
# 2. Restore the renamed directory
mv wp-content/plugins/all-in-one-wp-security-and-firewall.bak \
wp-content/plugins/all-in-one-wp-security-and-firewall
# 3. Restore the original .htaccess configuration
cp .htaccess.bak.* .htaccess
9. Complete diagnostic script and checklist#
9.1 forensic diagnostic script (wp-diagnostic.sh)#
Create the following script in your WordPress root directory to audit the health of your installation:
#!/bin/bash
# wp-diagnostic.sh - Forensic WordPress diagnostic
# Run as owner of files or root
set -euo pipefail
DOMAIN="${1:-localhost}"
WP_PATH="${2:-.}"
echo "=== WordPress Diagnostic: $DOMAIN ==="
echo ""
# 1. HTTP Test
echo "[1] Testing HTTP connections..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -I "https://$DOMAIN/wp-admin/")
echo " HTTP Status for /wp-admin/: $HTTP_CODE"
if [ "$HTTP_CODE" = "403" ]; then
echo " ⚠️ Warning: Block detected at the server/WAF layer (HTTP 403)"
elif [ "$HTTP_CODE" = "200" ]; then
echo " ✅ Status HTTP 200. If screen is blank, check PHP logs."
fi
# 2. Check Core
echo ""
echo "[2] Validating WordPress core..."
cd "$WP_PATH"
if wp core is-installed 2>/dev/null; then
echo " ✅ Core is installed"
wp core verify-checksums 2>/dev/null || echo " ⚠️ Warning: Core checksum verification failed!"
else
echo " ❌ Core not installed or database inaccessible."
fi
# 3. Active Plugins
echo ""
echo "[3] Top active plugins:"
wp plugin list --status=active --field=name 2>/dev/null | head -n 10
# 4. Check .htaccess
echo ""
echo "[4] Auditing .htaccess..."
if [ -f .htaccess ]; then
BLOCKS=$(grep -c "BEGIN" .htaccess)
echo " Identified blocks: $BLOCKS"
[ "$BLOCKS" -gt 1 ] && echo " ⚠️ Warning: Duplicate blocks detected in .htaccess"
else
echo " ℹ️ .htaccess file not found."
fi
# 5. Recent Logs
echo ""
echo "[5] Inspecting debug.log..."
if [ -f wp-content/debug.log ]; then
tail -n 5 wp-content/debug.log
else
echo " ℹ️ debug.log not found."
fi
echo ""
echo "=== End of Diagnostic ==="
9.2 checklist: WordPress admin locked#
Use this checklist to guide your mitigation process step by step:
- HTTP/Network:
- [ ] Run
curl -I https://domain.com/wp-admin/and validate the response code. - [ ] Check for static IP locks or active CDNs.
- Web Server:
- [ ] Inspect ModSecurity logs (
modsec_audit.log). - [ ] Validate Nginx configuration syntax (
nginx -t). - [ ] Monitor PHP and web server error logs.
- WordPress Core:
- [ ] Run
wp core is-installedandwp core verify-checksums. - [ ] Validate URL values in the database via
wp option get siteurlandhome. - Plugins:
- [ ] List active plugins.
- [ ] Deactivate security plugins using
--skip-pluginsif necessary. - [ ] Validate reactions by reactivating plugins individually.
- Files:
- [ ] Inspect duplicate rules in
.htaccess. - [ ] Fix file permissions (directories to 755, files to 644).
- [ ] Ensure correct ownership (e.g.,
www-data:www-data).
10. Production Takeaways and Operational Governance#
Blocking /wp-admin before login is not solved with random attempts. It's solved with a methodical analysis of network and application layers, forensic log auditing, and surgical WP-CLI execution.
By following a well-documented runbook, Mean Time to Recovery (MTTR) drops drastically, and critical credentials remain secure.
Was this article helpful?
Leave a quick reaction to help prioritize future technical guides:
This post is licensed under CC BY-NC.



Comments
Join the discussion below.
0 comments