Bcrypt vs Argon2: which password hash in 2026
Bcrypt and Argon2 are the two most widely used password hashing functions today. Both are designed to be slow and resistant to brute-force attacks, unlike MD5 or SHA-256 which are fast by design. Argon2 won the Password Hashing Competition in 2015 and is now the choice recommended by OWASP for new applications. Bcrypt remains an excellent, mature and widely supported option. This article spells out the differences precisely to help you decide.
Why a password hash is different
A classic cryptographic hash such as SHA-256 is designed to be fast: the goal is to hash gigabytes of data per second. For passwords, that property is a flaw: an attacker who obtains your user table can test billions of passwords per second on a GPU. A password hashing function (PHF) on the contrary aims to be:
- Slow by design, with an adjustable cost parameter
- Salted, to prevent rainbow tables and parallel attacks across multiple accounts
- Resistant to specialised hardware (GPU, FPGA, ASIC) to limit the adversarial speedup
The salt and the cost parameter are stored with the hash, in a single string typically of
the form $algo$params$salt$hash. This lets you raise the cost over time without
forcing immediate migration of old hashes.
Bcrypt: 1999, Blowfish, cost parameter
Bcrypt was designed by Niels Provos and David Mazières for OpenBSD in 1999. It is
based on the Blowfish cipher, taking advantage of its expensive table initialisation. Bcrypt
exposes a single parameter, cost (or rounds), which sets the iteration
count as 2^cost. Increasing cost by 1 doubles the compute time.
Typical output format:
$2y$12$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
| | | |
| | cost = 12 sel + hash en base64
| variante (2y = openbsd)
algo bcrypt
Bcrypt limits the input to 72 bytes: any longer password is silently truncated, a well-known pitfall. The usual workaround is to pre-hash with SHA-256 and base64-encode before bcrypt, but that can introduce problematic null bytes on some implementations. Argon2 has no such limit.
Argon2: 2015, PHC winner, 3 variants
Argon2 was designed by Alex Biryukov, Daniel Dinu and Dmitry Khovratovich. It won the Password Hashing Competition in July 2015 and is standardised by RFC 9106 (2021). Argon2 exposes three parameters:
- Memory cost (
m): amount of memory used, in KiB - Time cost (
t): number of iterations over the memory block - Parallelism (
p): number of parallel threads
Argon2 comes in three variants:
- Argon2d: data-dependent memory access. More resistant to GPU attacks, but vulnerable to side-channel attacks (timing, cache).
- Argon2i: data-independent memory access. Resistant to side-channels, slightly less resistant to GPU attacks.
- Argon2id: hybrid, starts in i mode then switches to d mode. Recommended by default by RFC 9106 and OWASP.
OWASP-recommended parameters in 2026 for Argon2id: m=19456 KiB (19 MiB),
t=2, p=1. Typical output format:
$argon2id$v=19$m=19456,t=2,p=1$c2VsX2FsZWF0b2lyZQ$aGFzaF9jYWxjdWxl
| | | | |
| | parametres sel base64 hash base64
| version
algo argon2id
Why Argon2id is recommended
Resistance to specialised hardware is the decisive criterion today. Bcrypt uses little memory (~4 KiB), which lets a high-end GPU test hundreds of thousands of hashes per second. Argon2id is memory-hard: forcing several MiB of memory per attempt drastically reduces the parallelism achievable on a GPU and makes the design of dedicated ASICs economically unprofitable.
Argon2id's hybrid mode also provides protection against side-channel attacks during the first half of the computation. That combination is what justifies its place as the default recommendation of OWASP, of NIST SP 800-63B (since the 2024 revision) and of RFC 9106.
Comparison table
| Criterion | Bcrypt | Argon2id |
|---|---|---|
| Year | 1999 | 2015 |
| Standardisation | De facto, USENIX 1999 | RFC 9106 (2021) |
| Parameters | cost | memory, time, parallelism |
| Memory used | ~4 KiB | Configurable (~19 MiB recommended) |
| Memory-hard | No | Yes |
| GPU resistance | Moderate | Strong |
| Side-channel resistance | Good (constant-time) | Good (id mode) |
| Input limit | 72 bytes | None |
| OWASP 2026 recommendation | Acceptable | Preferred |
| Ecosystem maturity | Very wide | Wide since ~2018 |
Performance and attack resistance
On a modern server, a bcrypt at cost=12 takes about 250 ms and an argon2id with OWASP parameters about 100-300 ms depending on the machine. Absolute time is not the criterion: what matters is the ratio between your cost (one calculation, once per login) and the attacker's (billions of computations on GPU to crack a dump).
On an RTX 4090, hashcat reaches around 200,000 bcrypt/s at cost=12, versus a few tens of thousands of argon2id at 19 MiB. For the same server-side compute time, Argon2id slows the attacker down 5 to 10 times more than bcrypt, and the gap widens with each new generation of GPUs.
PHP examples
PHP supports both natively via password_hash() and password_verify()
since PHP 7.2 for Argon2i (and 7.3 for Argon2id). The PHP constructor handles salt and format
automatically.
Bcrypt
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
$ok = password_verify($password, $hash);
if (password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 12])) {
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
}
Argon2id
$opts = [
'memory_cost' => 19456, // 19 MiB
'time_cost' => 2,
'threads' => 1,
];
$hash = password_hash($password, PASSWORD_ARGON2ID, $opts);
$ok = password_verify($password, $hash);
if (password_needs_rehash($hash, PASSWORD_ARGON2ID, $opts)) {
$hash = password_hash($password, PASSWORD_ARGON2ID, $opts);
}
You can generate or identify hashes of any kind with our hash generator and our hash identifier.
Recommendation
For a new application in 2026, choose Argon2id with the OWASP parameters as a
baseline (m=19456, t=2, p=1), adjusted to hit your target
time (typically 250 to 500 ms). If you maintain an existing bcrypt-based application, there is no
rush to migrate: bcrypt at cost=12 or higher remains safe in 2026. Take advantage of a
password_needs_rehash() at the next login to migrate active users to Argon2id
gradually.
Absolutely avoid plain MD5, SHA-1 and SHA-256 for passwords (see our MD5 vs SHA-256 comparison). None of these algorithms is designed for that purpose.
Frequently asked questions
Is bcrypt still safe in 2026?
Yes, provided you use a high enough cost (12 minimum, 14 if possible). Bcrypt has no known cryptographic flaw. Its only relative weakness compared to Argon2id is its small memory footprint, which makes it more accessible to GPU and FPGA attacks.
Should I migrate a bcrypt database to Argon2id?
No rush. A gradual migration with password_needs_rehash() is the recommended
approach: on each successful login, you re-hash the password with Argon2id. After a few
months, the majority of active users are migrated, and you can force a reset for dormant
accounts.
What is the right number of threads for Argon2id?
OWASP recommends p=1 by default. Raising p brings nothing if your
web server already handles many requests in parallel, and it complicates tuning. Prefer
instead to raise m (memory), which is the main lever for GPU resistance.
What is a "bcrypt decrypter"?
There is no such thing as a bcrypt decrypter: the function is one-way by design. Tools that claim to "decrypt" bcrypt merely test dictionaries of common passwords against the hash. That is exactly the same as what an attacker who got hold of your table would do.
Argon2i or Argon2id?
Argon2id in every case for passwords. Argon2i is slightly safer against side-channels but weaker against GPU attacks. Argon2id combines the strengths of both and is explicitly recommended by RFC 9106 for password hashing.
Should I add a pepper on top of the salt?
The salt is enough for the vast majority of applications. A pepper (a secret key stored outside the database and used as an HMAC before the hash) adds a layer in case the database leaks without compromise of the application server. Argon2id does not provide it natively, you have to compose it manually.