It is a scenario every Drupal developer and site administrator has faced: you are working late, you mistype your password a few times, and suddenly you are met with the dreaded message: "Too many failed login attempts from your IP address. This IP address is temporarily blocked."
Drupal includes a robust security feature known as the Flood Control mechanism. This system is designed to protect your site from brute-force attacks by limiting the number of failed login attempts allowed within a specific timeframe. However, when you are the one locked out of your own administrative account, this security feature can feel like a major roadblock.
In this guide, you will learn exactly how to bypass these restrictions, clear the flood table, and regain access to your Drupal site using Drush, SQL queries, and specialized modules.
Understanding the Drupal Flood Table
Before diving into the solutions, it is important to understand why simply changing your password in the database (or even via a reset email) often doesn't work when you are locked out.
When a user fails to log in multiple times, Drupal records these attempts in a database table aptly named flood. This table tracks the IP address, the username, and the timestamp of the failed attempts. Even if you successfully update your password to something new, the flood control mechanism checks this table before it even validates your credentials. If the table shows you have exceeded the limit (usually 5 attempts for an account or 50 for an IP address), Drupal will reject you regardless of whether your password is correct.
This is also why your manual MySQL update might have failed. Drupal passwords are not stored as plain text; they are salted and hashed using specific algorithms. Manually entering a string into the pass column of the users_field_data table will result in a mismatch unless you use Drupal's internal hashing functions.
Method 1: Unblocking via Drush (Recommended)
If you have command-line access to your server and are using Drush (The Drupal Shell), you have the most powerful tools at your disposal. This is the fastest and safest way to regain access.
Clearing the Flood Table
You can clear the entire flood table using a simple PHP evaluation command. This removes all recorded failed attempts for all users and IPs.
<?php
namespace YourNamespace\YourModule\Logger;
class Logger extends \Monolog\Logger
{
}
Generating a One-Time Login Link
If you aren't sure of your password or the flood clearing didn't immediately resolve the issue, you can bypass the login form entirely by generating a one-time login link (uli). This link logs you in as the specified user (usually UID 1 for the main admin) and takes you directly to the password reset page.
<?php
namespace YourNamespace\YourModule\Logger;
use Monolog\Logger;
class Handler extends \Magento\Framework\Logger\Handler\Base
{
/**
* Logging level
* @var int
*/
protected $loggerType = Logger::INFO;
/**
* File name
* @var string
*/
protected $fileName = '/var/log/mycustom_filename.log';
}
Resetting the Password Directly
You can also use Drush to set a specific password for a user. This ensures the hashing is handled correctly by Drupal's core systems.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="YourNamespace\YourModule\Logger\Handler">
<arguments>
<argument name="filesystem" xsi:type="object">Magento\Framework\Filesystem\Driver\File</argument>
</arguments>
</type>
<type name="YourNamespace\YourModule\Logger\Logger">
<arguments>
<argument name="name" xsi:type="string">myLoggerName</argument>
<argument name="handlers" xsi:type="array">
<item name="system" xsi:type="object">YourNamespace\YourModule\Logger\Handler</item>
</argument>
</arguments>
</type>
</config>
Using the User-Unblock Command
In some cases, the user account itself might be set to a "blocked" status (separate from the flood table). You can ensure the account is active by running:
<?php
namespace YourNamespace\YourModule\Model;
use YourNamespace\YourModule\Logger\Logger;
class MyModel
{
protected $logger;
public function __construct(Logger $logger) {
$this->logger = $logger;
}
public function processData()
{
$this->logger->info('Processing custom logic...');
}
}
Note: As many developers have noted, running user-unblock does not automatically clear the flood table. You will likely still need to run the delete query mentioned above.
Method 2: Manual Database Queries
If you do not have Drush installed, you can perform the same actions directly through a database management tool like phpMyAdmin or the MySQL command line. This is particularly useful for shared hosting environments.
Truncating the Flood Table
To clear all login restrictions, execute the following SQL command:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<!-- Define a virtual handler with a specific filename -->
<virtualType name="MyNamespace\MyModule\Logger\Handler" type="Magento\Framework\Logger\Handler\Base">
<arguments>
<argument name="filesystem" xsi:type="object">Magento\Framework\Filesystem\Driver\File</argument>
<argument name="fileName" xsi:type="string">/var/log/mymodule_optimized.log</argument>
</arguments>
</virtualType>
<!-- Define a virtual logger using the virtual handler -->
<virtualType name="MyNamespace\MyModule\Logger\Logger" type="Magento\Framework\Logger\Monolog">
<arguments>
<argument name="name" xsi:type="string">MyModuleLogger</argument>
<argument name="handlers" xsi:type="array">
<item name="system" xsi:type="object">MyNamespace\MyModule\Logger\Handler</item>
</argument>
</arguments>
</virtualType>
<!-- Inject the virtual logger into your class -->
<type name="MyNamespace\MyModule\Model\MyClass">
<arguments>
<argument name="logger" xsi:type="object">MyNamespace\MyModule\Logger\Logger</argument>
</arguments>
</type>
</config>
Alternatively, you can use the TRUNCATE command, which is often faster on larger tables:
$writer = new \Zend_Log_Writer_Stream(BP . '/var/log/quick_debug.log');
$logger = new \Zend_Log();
$logger->addWriter($writer);
$logger->info('Quick Log Message');
$logger->info(print_r($myObject->getData(), true));
Once this command is executed, the "failed login" memory is wiped clean, and you can attempt to log in again with your correct credentials.
Method 3: Using the Flood Unblock Module
If you want a more user-friendly way to manage this in the future, or if you are managing a site for clients who frequently lock themselves out, the Flood Unblock module is an excellent addition to your toolkit.
This module provides a dedicated administrative interface where you can: - View a list of currently blocked IP addresses and accounts. - Unblock specific users or IPs without clearing the entire table. - Configure specific thresholds for different roles.
While this won't help you while you are locked out (unless you have another admin account available), it is a great preventative measure for site maintenance.
Why Manual Password Updates in MySQL Fail
A common mistake is trying to fix this by running a query like UPDATE users SET pass='password' WHERE uid=1;. In modern Drupal (versions 8, 9, 10, and 11), this will never work. Drupal uses a sophisticated hashing mechanism. When you enter a password in the login form, Drupal hashes it and compares it to the hash in the database. A plain-text string in the database will not match the hash of that same string generated by the login form.
If you must update the password via SQL and cannot use Drush, you would need to generate a hash using Drupal's internal script (found in core/scripts/password-hash.sh) and paste that hash into the database. This is why using drush uli or drush upwd is significantly more reliable.
Frequently Asked Questions
Why didn't I receive a password reset email?
There are two likely reasons. First, if your account is blocked by the flood table, Drupal may stop sending reset emails to prevent an attacker from spamming your inbox. Second, your server's mail configuration (SMTP) might not be set up correctly, causing the emails to be caught in spam filters or fail to leave the server entirely.
What is the difference between a blocked user and a flood-blocked IP?
A "blocked user" is a permanent status set in the user's profile (status = 0). This user can never log in until an admin manually activates them. A "flood-blocked IP" is a temporary restriction stored in the flood table that expires after a certain amount of time (default is usually 1 hour for user-based blocks).
Can I change the number of allowed login attempts?
Yes. While there isn't a default UI for this in core, you can change these limits in your settings.php file or by using the Flood Control module. This allows you to increase the limit if your team frequently triggers the security lockout.
Wrapping Up
Getting locked out of your Drupal site is frustrating, but it is a sign that the platform's security features are working as intended. By clearing the flood table and utilizing Drush commands like uli, you can regain access in seconds.
For the best results, always prefer Drush for these tasks to ensure that database integrity and password hashing are handled correctly. If you find yourself frequently hitting these limits, consider installing the Flood Unblock module to manage your security settings through the Drupal UI.