toolhq.io

All posts
6 min readby Jameel Haider

The bcrypt work factor explained: cost, timing, and the 72-byte truncation

bcrypt deliberately makes password hashing slow, and the work factor is the dial that sets how slow. Turn it up and every hash takes longer to compute, which is the whole point: an attacker who steals your password database has to pay that cost for every guess. Choosing the number correctly, and knowing the one input limit that silently discards part of a password, is the difference between a hash that protects users and one that only looks like it does.

What the work factor is

A bcrypt hash encodes its parameters in the string itself. A hash beginning $2b$12$ uses variant 2b with a cost of 12. That cost, also called the work factor or rounds, is an exponent: the key setup runs 2^cost iterations.

Because it is a power of two, each increment doubles the work. Cost 12 does twice the work of cost 11 and four times the work of cost 10. This is what lets the algorithm keep pace with faster hardware over the years: you raise the cost by one every time machines get roughly twice as fast, and the attacker's advantage stays flat.

How cost maps to time

The actual time per hash depends on your hardware, but the doubling relationship is exact. On a representative modern server core, a rough picture looks like this:

CostRelative workApprox time per hash
101x~50 ms
112x~100 ms
124x~200 ms
138x~400 ms
1416x~800 ms

Treat the millisecond figures as illustrative; measure on your own hardware. The ratios are what hold: moving from 10 to 14 makes each hash sixteen times more expensive.

Choosing a cost in 2026

The standard advice is to pick the highest cost your server can tolerate for a login, where "tolerate" usually means a hash taking somewhere between 100 and 500 milliseconds. That band is slow enough to punish bulk guessing but fast enough that a legitimate login does not feel delayed, and it leaves headroom for traffic spikes.

In 2026 that lands most deployments at cost 12 or 13 on typical server hardware. The honest method is not to copy a number but to benchmark: run bcrypt at increasing costs on your production-class hardware and choose the highest cost that stays under your latency budget for a single hash. Re-benchmark every couple of years and raise the cost as hardware improves. Because the cost is stored in the hash, you can verify old hashes at their original cost and transparently re-hash a user's password at the new cost on their next successful login.

Do not go so high that login latency enables denial of service, where attackers flood your login endpoint to exhaust CPU. The cost protects the stolen database, not the live endpoint; rate limiting protects the endpoint.

The 72-byte truncation gotcha

Here is the trap that surprises people. bcrypt only considers the first 72 bytes of the input. Anything beyond that is silently ignored. It does not error, it does not warn; it just hashes a truncated password.

Two consequences follow:

  • Long passwords are weaker than they look. A 100-character passphrase is protected only by its first 72 bytes. The tail contributes nothing.
  • Bytes, not characters. The limit is 72 bytes, and multi-byte UTF-8 characters eat into it fast. An emoji is four bytes; many accented or non-Latin characters are two or three. A password that looks like 30 characters can exceed 72 bytes, so the cutoff lands mid-password in a place the user never sees.

A related and nastier edge case: some bcrypt implementations historically mishandled a NUL byte in the input, truncating at the NUL. Modern libraries using the 2b variant handle length correctly within the 72-byte window, but the window itself is a hard limit of the algorithm, not a bug.

The common mitigation is to pre-hash the password with SHA-256 and feed the digest into bcrypt, which collapses any length into a fixed short input before the 72-byte limit applies. Do this consistently, since it changes the stored format. Alternatively, reach for a newer hash such as Argon2 or scrypt, which have no such input limit and are the current recommendation for new systems, with bcrypt remaining a reasonable and well understood choice.

Whatever hash you store, the strength still starts with the password the user chose. To gauge how much real entropy a candidate password carries before any hashing, check it with the Password Strength tool, which runs entirely in your browser and never transmits what you type.