logo

The gap in our max password length advice

Characters and bytes aren't the same thing

Joel Clermont
Joel Clermont
2026-10-13

In an earlier tip, I explained why Laravel offers a max password length rule. Bcrypt only uses the first 72 bytes of a password and silently ignores the rest, so it's better to reject a long password up front.

That advice still stands, but it has a gap.

The max rule counts characters, not bytes. Under the hood, Password::max(72) uses mb_strlen(), while bcrypt counts raw bytes.

For plain ASCII, those are the same number, but the count is not the same for accented letters or emoji. So a password with accented letters can pass max(72) and still get truncated by bcrypt.

Laravel doesn't have a built-in rule that counts bytes on a regular string. But the Password rule lets you add your own checks with rules(), and you can register the whole thing once with Password::defaults().

// in AppServiceProvider::boot()
Password::defaults(function () {
    return Password::min(8)
        ->rules([
            function (string $attribute, mixed $value, Closure $fail) {
                // purposely using this function to count raw bytes, not characters
                if (strlen($value) > 72) {
                    $fail('The :attribute is too long.');
                }
            },
        ]);
});

Now every password field uses the same rule.

'password' => ['required', 'confirmed', Password::defaults()],

Here to help,

Joel

P.S. Silent defaults like this are easy to miss until they bite. Our security book helps you spot the ones worth changing in your app.

Toss a coin in the jar if you found this helpful.
Want a tip like this in your inbox every weekday? Sign up below 👇🏼
email
No spam. Only real-world advice.