Argon2id vs bcrypt vs scrypt vs PBKDF2: Password Hashing in 2026
Which password hashing algorithm should you use? A practical comparison of Argon2id, bcrypt, scrypt and PBKDF2 with OWASP-recommended parameters, hash formats, pitfalls and migration steps.
By Abdessamad Bettal··6 min read
Key takeaways
- Argon2id is the default choice for new systems. OWASP's minimum: 19 MiB of memory, 2 iterations, 1 degree of parallelism (
m=19456,t=2,p=1). - bcrypt is still acceptable at cost 10 or higher (12 is common today), but it silently ignores everything after the first 72 bytes of a password.
- scrypt is a solid memory-hard alternative:
N=2^17, r=8, p=1(128 MiB). - PBKDF2 is the choice when you need FIPS-140 compliance: use HMAC-SHA-256 with at least 600,000 iterations.
- Never store passwords with plain SHA-256, MD5 or reversible encryption. Fast hashes run at billions of guesses per second on a GPU; password hashes are designed to run at thousands.
When a database leaks, the password hashes are what stand between the attacker and your users' accounts — including their accounts on *other* sites, since people reuse passwords. A good password hash cannot stop a weak password from being guessed, but it can make each guess so expensive that guessing millions of them becomes impractical.
That is the difference between a general-purpose hash and a password hash. SHA-256 is built to be fast: a single high-end GPU computes on the order of 20 billion SHA-256 hashes per second, and over 100 billion MD5 hashes. Password hashing functions are built to be slow on purpose, to use a unique salt per password so identical passwords produce different hashes, and — in the modern ones — to require lots of memory, which is the resource GPUs and ASICs have least of per core.
The short answer
| Algorithm | Year | Memory-hard | Recommended minimum (OWASP) | Use when |
|---|---|---|---|---|
| Argon2id | 2015 | Yes | m=19 MiB, t=2, p=1 | Default for new systems |
| scrypt | 2009 | Yes | N=2¹⁷, r=8, p=1 (128 MiB) | Argon2 unavailable |
| bcrypt | 1999 | No (4 KiB) | Cost 10 (12 common) | Existing systems, broad library support |
| PBKDF2 | 2000 | No | SHA-256 × 600,000 | FIPS-140 compliance required |
Argon2id: the modern default
Argon2 won the Password Hashing Competition in 2015 and is standardized in RFC 9106. It comes in three variants: Argon2d (maximizes GPU resistance but is vulnerable to side-channel attacks), Argon2i (side-channel resistant but weaker against trade-off attacks), and Argon2id, a hybrid that is the one you should use. It has three tuning knobs:
- m — memory in KiB. This is the main defense: each guess must fill and repeatedly read this much RAM.
- t — number of passes over that memory (time cost).
- p — degree of parallelism (lanes).
OWASP's baseline is m=19456 (19 MiB), t=2, p=1. It lists equivalent trade-offs if memory is scarce: m=12288,t=3, m=9216,t=4 or m=7168,t=5. RFC 9106 itself suggests far more — 64 MiB with t=3 as its "memory-constrained" option — so treat OWASP's numbers as a floor and raise memory until a login takes roughly a quarter to half a second on your servers.
Argon2 hashes are stored in the PHC string format, which keeps the algorithm, version, parameters and salt next to the hash:
$argon2id$v=19$m=19456,t=2,p=1$cGVwcGVyLWZyZWUtc2FsdA$lPcgsmHYK3WDaSWfvRMBw7k4nzggT3pkOBenX1/wiN8
└ variant └ ver └ parameters └ salt (Base64) └ 32-byte hash (Base64)That is the Argon2id hash of correct horse battery staple with the salt pepper-free-salt (Base64 cGVwcGVyLWZyZWUtc2FsdA). Reproduce it in our Argon2 hash generator by entering that salt with t=2, m=19456, p=1, or with the reference command-line tool:
printf 'correct horse battery staple' | argon2 pepper-free-salt -id -t 2 -k 19456 -p 1 -l 32 -eIn production, use a random 16-byte salt per password — the library's hash() function does this for you. Because parameters travel with the hash, you can raise them later without breaking old hashes.
bcrypt: old, battle-tested, with one big gotcha
bcrypt (1999) is built on the Blowfish cipher's expensive key setup. Its single parameter, the cost, is a base-2 logarithm: each +1 doubles the work. It uses only 4 KiB of memory, so it is not memory-hard, but it has resisted GPU acceleration better than its age suggests and is available in every language.
$2b$12$JA3RR0XJEU1ovh9epjsDDeeOCsIvM4kHQkSsjN/mhQ3O4a95Ckh16
│ │ └ 22 chars: 128-bit salt
│ └ cost 12 → 2^12 = 4096 rounds of key expansion
└ version ($2b$ is current) └ last 31 chars: 184-bit hashThe 72-byte limit
bcrypt only uses the first 72 bytes of the password. Anything after that is silently ignored, so two long passwords that share a 72-byte prefix produce matching hashes. We verified this with bcryptjs: a hash of 72 × a + XYZ validates against 72 × a + different. This matters for long passphrases and for multi-byte UTF-8 text, where 72 bytes can be as few as 18 emoji.
OWASP's minimum is cost 10; cost 12 is a common modern choice. Measure it: pick the highest cost that keeps a hash around 250 ms on your hardware.
scrypt: memory-hard and mature
scrypt (Colin Percival, 2009; RFC 7914) was the first widely used memory-hard function and is the KDF behind many cryptocurrency wallets and Litecoin's proof of work. Its parameters are N (CPU/memory cost, a power of two), r (block size) and p (parallelism). Memory used is roughly 128 × N × r bytes, so OWASP's recommended N=2^17, r=8, p=1 needs 128 MiB per hash.
scrypt is a good choice where Argon2 is not available — for example Node.js ships crypto.scrypt natively. Its weakness is that memory and time are coupled through N, so you cannot raise one without the other.
PBKDF2: the compliance choice
PBKDF2 (RFC 8018, NIST SP 800-132) simply iterates HMAC many times. It needs almost no memory, which makes it the most GPU-friendly of the four — and therefore the weakest per unit of server time. Its advantage is that it is approved under FIPS 140, so regulated environments often must use it. It is also built into Web Crypto, which is why browser-side tools (including our own AES encryptor) use it for key derivation.
OWASP iteration minimums for 2026:
- PBKDF2-HMAC-SHA-256: 600,000 iterations
- PBKDF2-HMAC-SHA-512: 210,000 iterations
- PBKDF2-HMAC-SHA-1: 1,300,000 iterations (only for legacy compatibility)
Mistakes that undo a good algorithm
- Reusing or omitting salts. Every password needs its own random salt (16 bytes is plenty). All four algorithms handle this for you when you use the library's high-level
hash()function — don't roll your own. - Comparing hashes with `==`. Use the library's
verify()function, which compares in constant time. - Setting parameters once and forgetting them. Hardware gets faster. Re-measure every year or two and raise the cost; the stored parameters make this painless.
- Unbounded password length with Argon2 or PBKDF2. Accept long passwords, but cap input (for example at 1,024 characters) so attackers can't submit megabyte-long passwords to burn CPU.
- Encrypting instead of hashing. If the server can decrypt passwords, so can whoever steals the server's key.
A pepper — a secret key stored outside the database (in an HSM, KMS or environment secret) and mixed in with HMAC — adds protection if only the database leaks. It is optional and complements, never replaces, a proper password hash.
Migrating from MD5, SHA-1 or unsalted SHA-256
You cannot rehash old hashes without the original passwords — but you don't have to wait for every user to log in:
- Wrap immediately. For every legacy hash, compute
argon2id(old_hash)and store that, marked with a version flag. Now every account is protected by Argon2id today. - Verify through both layers. At login, compute the legacy hash of the submitted password, then verify it against the wrapped Argon2id hash.
- Upgrade on login. On successful login, replace the wrapped hash with a direct
argon2id(password). - Expire stragglers. After a set period, force password resets for accounts that never logged in.
Unsure how strong your users' passwords need to be in the first place? See how password entropy is calculated.
Frequently asked questions
Is Argon2 better than bcrypt?
+
For new systems, yes. Argon2id is memory-hard, which makes GPU and ASIC cracking far more expensive, it has no 72-byte password limit, and its parameters can be tuned independently. bcrypt remains acceptable for existing systems at cost 10 or higher.
What bcrypt cost factor should I use in 2026?
+
OWASP's minimum is 10. Many applications use 12. The right value is the highest cost that keeps a single hash at roughly 250 ms on your production hardware; each increase of 1 doubles the time.
How many PBKDF2 iterations are recommended?
+
OWASP recommends at least 600,000 iterations for PBKDF2-HMAC-SHA-256 and 210,000 for PBKDF2-HMAC-SHA-512.
Is SHA-256 good enough for passwords?
+
No. SHA-256 is designed to be fast, so a single GPU can test billions of guesses per second. Even with a salt, that is far too fast. Use Argon2id, scrypt, bcrypt or high-iteration PBKDF2.
Do I need to store the salt separately?
+
No. Modern formats such as the Argon2 PHC string and the bcrypt modular crypt string embed the salt and parameters in the stored hash. Salts are not secret; they only need to be unique.
Tools used in this guide
Argon2 Hasher
The password-hashing competition winner, memory-hard
BCRYPT · COSTBcrypt Hasher
Hash and verify passwords with the bcrypt standard
SCRYPT · N/r/pScrypt Calculator
Memory-hard key derivation with tunable N, r, p
PBKDF2 · HMAC-SHA-2PBKDF2 Derivation
Derive keys from passwords with salt and iterations
Encoding vs Encryption vs Hashing: The Difference, With Examples
Encoding, encryption and hashing all turn data into gibberish, but only one keeps secrets. Learn the difference with real Base64, AES and SHA-256 examples and when to use each.
6 MIN READSYMMETRIC · AESAES-GCM vs CBC vs CTR vs ECB: Which AES Mode Should You Use?
AES is only as safe as its mode. Compare ECB, CBC, CTR and GCM — how each works, how each fails, and why AES-GCM (or ChaCha20-Poly1305) is the right default in 2026.
7 MIN READRANDOMNESS · PASSWORDSPassword Entropy Explained: How Strong Is Your Password, Really?
How password strength is actually measured: the entropy formula, a crack-time table for random passwords and passphrases, why human-chosen passwords score far lower, and current NIST rules.
6 MIN READ