Argon2id vs bcrypt: which password hash to use in 2026

Argon2id is memory hard and the modern default; bcrypt is CPU hard, battle tested and capped at 72 bytes. Parameters, code and migration path.

Short answer

Use Argon2id for new systems: it is memory hard, standardised in RFC 9106 and the first choice in the OWASP Password Storage Cheat Sheet, with a minimum of 19 MiB memory, 2 iterations and parallelism 1. bcrypt is still acceptable when Argon2id is not available, at cost 10 or higher, but its small fixed memory makes it cheaper to attack on GPUs and it only uses the first 72 bytes of input. If you have bcrypt hashes today, do not panic or mass reset: rehash to Argon2id on the next successful login.

Argon2idbcrypt
OriginPassword Hashing Competition winner, 2015Provos and Mazieres, 1999
StandardRFC 9106 (2021)No RFC; de facto via OpenBSD
HardnessMemory hard and CPU hardCPU hard, about 4 KB fixed memory
TunableMemory (m), iterations (t), parallelism (p)Cost factor only (2^cost rounds)
OWASP minimumm=19 MiB, t=2, p=1 (or m=46 MiB, t=1)Cost 10
Input limitEffectively none (2^32 - 1 bytes)72 bytes, longer input truncated or rejected
GPU/ASIC resistanceStrong, scales with memoryModerate
Encoded format$argon2id$v=19$m=...,t=...,p=...$salt$hash$2b$12$ + 22 char salt + 31 char hash
Library supportGood, not universal in older stacksEverywhere
FIPS 140 validatedNoNo (use PBKDF2 if FIPS is mandatory)

01How each slows an attacker

bcrypt is built on the Blowfish key schedule. It runs an expensive setup 2^cost times, so each +1 doubles the work. Its working memory is small and fixed (about 4 KB), which means a GPU can run many guesses in parallel cheaply.

Argon2id fills a block of memory of size m, makes t passes over it with data-dependent and data-independent addressing (the 'id' hybrid resists both GPU cracking and side channels), and can split work across p lanes. An attacker must pay for m bytes of fast memory per guess, which is what makes large-scale cracking expensive. Argon2d and Argon2i also exist; for password hashing use Argon2id.

!The 72 byte trap

bcrypt only uses the first 72 bytes. Long passphrases, or a pre-hash concatenated with a username, silently lose their tail in some libraries; others now raise an error. If you must pre-hash for bcrypt, base64 encode an HMAC-SHA-256 so no raw zero bytes reach implementations that stop at NUL.

02Hash and verify in both (Python)

Argon2id with argon2-cffipython
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError

ph = PasswordHasher(time_cost=2, memory_cost=19456, parallelism=1)  # memory in KiB

stored = ph.hash("correct horse battery staple")
# '$argon2id$v=19$m=19456,t=2,p=1$<salt>$<hash>'

def check(stored: str, password: str) -> bool:
    try:
        ph.verify(stored, password)
    except VerifyMismatchError:
        return False
    if ph.check_needs_rehash(stored):
        pass  # parameters changed: rehash and save
    return True
bcrypt with the bcrypt packagepython
import bcrypt

pw = "correct horse battery staple".encode()
if len(pw) > 72:
    raise ValueError("bcrypt only uses 72 bytes")

stored = bcrypt.hashpw(pw, bcrypt.gensalt(rounds=12))
# b'$2b$12$<22 char salt><31 char hash>'

def check(stored: bytes, password: str) -> bool:
    return bcrypt.checkpw(password.encode(), stored)

Both verify functions compare in constant time and read the salt and parameters from the stored string, so you never store them separately.

03When to pick which, and how to tune

  • New system with a maintained Argon2 library: Argon2id.
  • Tune on your production hardware: raise memory first, then iterations, until a hash takes roughly 200 to 500 ms at your login peak.
  • Watch memory under load: 64 MiB per hash times 200 concurrent logins is 12.5 GiB. Cap concurrency or lower m with higher t.
  • Stuck on a platform with only bcrypt: bcrypt at cost 12 or more, with an explicit 72 byte check.
  • FIPS 140 mandated: PBKDF2-HMAC-SHA-256 with at least 600,000 iterations, per OWASP.
  • Add a pepper (secret key held in a KMS or HSM, applied as HMAC before hashing) if a database-only leak is a realistic threat.

04Migrating bcrypt to Argon2id

  1. Store the full encoded string; the prefix ($2b$ or $argon2id$) tells you which algorithm to verify with.
  2. On successful login with a bcrypt hash, rehash the plaintext you just verified with Argon2id and overwrite.
  3. For dormant accounts, optionally wrap: store argon2id(bcrypt_hash) and verify by computing bcrypt then Argon2id, so old hashes gain memory hardness without the password.
  4. Track the share of each prefix and, after a deadline, force reset for any account still on bcrypt.
iNever do this

Do not reset everyone's password to migrate, do not use plain SHA-256 or MD5 with a salt, and do not invent your own iteration scheme. Fast hashes are trivially brute forced on GPUs.

05How to say it in an interview

“How to say it in the room

Both are deliberately slow, salted password hashes, but bcrypt only costs CPU with a tiny fixed memory, so GPUs attack it well, and it ignores input past 72 bytes. Argon2id costs memory as well as time, which is what makes mass cracking expensive, and it is standardised in RFC 9106. I default to Argon2id at OWASP parameters or above, tuned on real hardware, and migrate bcrypt users by rehashing on their next successful login.

Questions people ask

Q1Is bcrypt still secure?+

Yes, at cost 10 or higher it is still considered acceptable. It is weaker than Argon2id against GPU and ASIC attackers because it uses little memory, and it has the 72 byte input limit.

Q2What Argon2id parameters should I use?+

OWASP gives equivalent minimums such as m=19 MiB with t=2, or m=46 MiB with t=1, both with p=1. RFC 9106 recommends m=64 MiB, t=3, p=4 where memory is constrained, and m=2 GiB, t=1, p=4 otherwise. Tune upward on your own hardware.

Q3Argon2i, Argon2d or Argon2id?+

Argon2id. Argon2d is fastest to compute for defenders but vulnerable to side channels, Argon2i resists side channels but is weaker against GPU tradeoff attacks. Argon2id mixes both and is what RFC 9106 recommends.

Q4What about scrypt?+

scrypt is also memory hard and is OWASP's next choice after Argon2id. It is fine if your platform has it and not Argon2id, with N=2^17, r=8, p=1 as the suggested minimum.

Q5Do I need a salt with Argon2id or bcrypt?+

Yes, and both libraries generate a random salt for you and embed it in the output string. Do not supply a fixed salt. A pepper is a separate, optional server-side secret.

Go deeper

Terms on this page