Every time you create a password on a website, that password needs to be stored β but storing it in plain text would be catastrophic if the database was ever leaked. Bcrypt is one of the algorithms designed to make stored passwords secure even when attackers get hold of the database. Here's how it works and why it matters.
In This Guide
What Is Bcrypt?
Bcrypt is a password hashing function created by Niels Provos and David Mazières in 1999, based on the Blowfish cipher. It was designed specifically for one purpose: storing passwords securely. Unlike general-purpose hash functions, bcrypt is intentionally slow and computationally expensive, making it resistant to brute-force attacks even when a database of hashed passwords is stolen.
You can generate and verify bcrypt hashes using our browser-based bcrypt generator β no installation required.
Why Not Just Use SHA-256?
SHA-256 is a general-purpose cryptographic hash function designed to be fast. Very fast. A modern GPU can compute billions of SHA-256 hashes per second. If an attacker gets a database of SHA-256 password hashes, they can try billions of guesses per second until they find matches β and most common passwords will be found within minutes or hours.
MD5 is even worse and should never be used for passwords under any circumstances. Even SHA-512 is too fast for password storage.
Bcrypt is deliberately slow by design. With cost factor 10, a single bcrypt hash takes about 100ms on modern hardware. That's ~10 hashes per second β billions of times slower than SHA-256. An attacker who steals a bcrypt database can only try a handful of passwords per second per core.
How Bcrypt Works
Bcrypt does three things that plain hashes don't:
Salt: Bcrypt automatically generates a unique random salt for each hash. The salt is embedded in the output hash. This means two users with the same password will have completely different hashes, and rainbow table attacks (precomputed hash dictionaries) are impossible.
Adaptive cost: The cost factor controls how many rounds of key scheduling are performed. Each increment doubles the work required. This allows the cost to be increased over time as hardware gets faster, keeping bcrypt secure as computing power grows.
Self-contained output: The bcrypt output contains the version, cost factor, salt, and hash in a single 60-character string. Everything needed to verify a password is in the hash itself β no separate salt storage needed.
Choosing the Right Cost Factor
OWASP recommends cost factor 10 as the minimum for most applications in 2026 β this produces a hash in about 100ms on a modern server. Cost 12 takes about 400ms and is appropriate for high-security applications where slightly slower login is acceptable.
The right cost is the highest value your server can handle within an acceptable login time β typically targeting 100β300ms. As hardware improves, you should periodically increase the cost factor and re-hash passwords when users next log in.
Never use a cost factor below 8 in production. For testing and development, cost 8 is fine to keep things fast.
Reading a Bcrypt Hash
A bcrypt hash looks like: $2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
Breaking it down: $2b$ is the bcrypt version (2b is current). $10$ is the cost factor. The next 22 characters (N9qo8uLOickgx2ZMRZoMye) are the base64-encoded salt. The remaining 31 characters are the hash. The full output is always exactly 60 characters.
Bcrypt vs Argon2 vs scrypt
All three are good choices for password hashing. Bcrypt is the most widely supported and has the longest security track record. Argon2 (winner of the Password Hashing Competition in 2015) is the modern recommendation β it's memory-hard, making it more resistant to GPU and ASIC attacks. scrypt is also memory-hard and a solid choice.
If you're starting a new project, Argon2id is the current best practice recommendation from OWASP. For existing systems using bcrypt, there's no urgent reason to migrate β bcrypt remains secure when used correctly.
In all cases: never use MD5, SHA-1, or plain SHA-256/512 for passwords. Use a dedicated password hashing function.
Common Bcrypt Implementation Pitfalls
Most bcrypt failures are implementation issues rather than algorithm flaws. The best-known one is the 72-byte input limit: bcrypt silently ignores everything after the first 72 bytes of a password, so two very long passphrases can hash identically. If you must accept long passphrases, pre-hash them with SHA-256 and feed the hex digest to bcrypt β a common pattern (used, for example, by Django's bcrypt_sha256 hasher) β or switch to a scheme without the limit. Other frequent mistakes: using a fixed salt or no salt, writing hashes to logs during debugging (they are password-equivalent), and assuming every library encodes the output the same way.
Verify your library's version prefix: bcrypt hashes start with $2a$, $2b$, or $2y$, and some older implementations have edge-case bugs with passwords containing high bytes. Confirm that the prefix your library produces matches what it accepts, or validation can fail intermittently for reasons that have nothing to do with the password itself.
Where Bcrypt Is Used in Practice
Bcrypt powers password storage in countless production systems: WordPress (cost 10 via wp_hash_password), Django's default hasher, many Node.js and Rails applications, and PostgreSQL's pgcrypto extension. It is also why some breached databases resist cracking while others fall immediately: the LinkedIn and Adobe leaks used weaker schemes, which is why so many of those passwords were recovered, whereas bcrypt-protected dumps typically yield only the weakest passwords even years after disclosure.
If you audit a legacy system, check the hash format before assuming the worst β a $2b$ prefix means passwords are probably safe, while unsalted MD5 or SHA-1 output means the dump is effectively a plain-text list. Migrating the latter to bcrypt (or Argon2id) should be prioritised in the next sprint, and re-hashing on login is the standard way to make the migration painless.
How Password Cracking Works (and Why Bcrypt Stops It)
Attackers crack stolen hashes in three stages. First they run every word in a dictionary plus common mutations against the dump β this recovers weak and common passwords in seconds. Next come rainbow tables for unsalted hashes, which swap computation for memory by precomputing hashes of the most likely passwords. Finally, brute force walks through every possible combination, with GPUs and specialised hardware pushing billions of guesses per second.
Against unsalted MD5 or SHA-1, those stages succeed at scale; against SHA-256 they are slower but still practical for common passwords. Bcrypt breaks the economics at every stage: the per-guess cost of 100ms or more means a GPU that manages billions of fast hashes per second manages only a handful of bcrypt hashes, and the unique per-password salt makes rainbow tables useless, because every hash requires its own table.
The result is not that bcrypt is uncrackable β it is that cracking becomes so expensive that only the weakest passwords are worth recovering. That is the design goal: make the attack cost more than the account is worth, and let the work factor scale the cost up as hardware improves.
Upgrading a Legacy Password Store to Bcrypt Without Locking Anyone Out
Real projects rarely start with bcrypt; they start with whatever the original developer chose, often md5(password) or sha256(password + salt). The upgrade trick is transparent re-hashing on login: when a user signs in successfully, detect that their hash uses the old scheme, verify against it, then immediately replace it with a fresh bcrypt hash (or Argon2id). The user notices nothing, and within one login cycle your entire active user base has migrated.
Do not attempt a bulk offline migration of legacy hashes to bcrypt without the original plaintext passwords β it is cryptographically impossible to convert a hash of one scheme into a hash of another, and anyone who promises a converter is describing a different, insecure scheme. Bulk conversion only works at the moment the password is presented, which is exactly what re-hashing on login does.
Common Misconceptions About Bcrypt
"Bcrypt is encryption, so I can decrypt the password later." No β bcrypt is a one-way hash. There is no key, and no operation that recovers the original password. Any tool that claims to "decrypt" a bcrypt hash is actually running guesses through the hash function until one matches.
"The salt must be kept secret." The salt exists to defeat precomputation, not to hide the hash. It is stored inside the hash string precisely because secrecy is unnecessary. What must stay secret is the password; the hash, salt, and cost factor are all safe to keep in the same database column.
"A higher cost factor is always better." A cost factor that takes five seconds per login invites denial of service β an attacker who knows your users' emails can burn your CPU by triggering logins, and your own users will abandon slow sign-ins. Choose the highest factor your server tolerates at the login rate you expect, measure it on your real hardware, and re-benchmark when you upgrade.
Bcrypt and 2FA: Two Layers, Different Jobs
Bcrypt protects passwords at rest; 2FA protects the login step in motion. They answer different questions: bcrypt decides what happens if your database leaks, while 2FA decides whether a stolen password is enough to get in. A breach-resistant hash without 2FA still allows password-reuse attacks; 2FA without good hashing still exposes plaintext-equivalent passwords in a leak.
For your own accounts, both layers matter. Store your users' passwords with a slow, salted, adaptive hash, and offer TOTP as an opt-in with a clear setup flow. The same habit applies to you: before trusting a service, check that it hashes with bcrypt or better and lets you enable 2FA.