Comparison
Security
Password Storage

bcrypt vs Argon2 vs PBKDF2

All three are purpose-built password hashing functions — far safer than MD5 or SHA-256 for storing passwords. The right choice depends on your framework, compliance needs, and hardware.

New to password hashing? Start with the how password hashing works guide before diving into algorithm comparisons.

Quick Answer

Use Argon2id for new systems — it is memory-hard, GPU-resistant, and recommended by OWASP and NIST. Use bcrypt if your stack has mature bcrypt support and you need proven, widely-deployed security. Use PBKDF2 only when FIPS 140-2 compliance requires it. Never use MD5, SHA-1, or plain SHA-256 for passwords.

Quick Verdict

Argon2id

Best for new systems

  • Memory-hard (GPU/ASIC-resistant)
  • OWASP & NIST recommended
  • No password length limit
  • Password Hashing Competition winner
  • ~Less universally supported than bcrypt
bcrypt

Best fallback / legacy

  • 25+ years of real-world validation
  • Universal framework support
  • Self-contained (salt built-in)
  • ~72-byte password limit
  • ~CPU-only hardness (no memory cost)
PBKDF2

Compliance use only

  • FIPS 140-2 / NIST SP 800-132 compliant
  • Available in every language
  • ~Not memory-hard
  • ~Weaker against GPU attacks
  • ~Requires very high iteration counts

Side-by-Side Comparison

AspectbcryptArgon2idPBKDF2
Introduced19992015 (PHC winner)2000 (RFC 2898)
Memory-hardNoYes (configurable)No
GPU / ASIC resistancePartial (CPU-focused)StrongWeak
Hardness parametersCost factor (work factor)Time cost, memory cost, parallelismIteration count, PRF algorithm
Salt handlingBuilt-in (auto-generated)Built-in (auto-generated)Manual (caller provides)
Password length limit72 bytes (silent truncation)No limitNo limit
FIPS 140-2 compliantNoNoYes
OWASP recommendedYes (fallback)Yes (preferred)Yes (compliance)
Framework supportUniversalGrowing (most modern frameworks)Universal
OWASP iteration targets (2026)Cost 10 minimumm=19MiB, t=2, p=1600,000 iterations (SHA-256)
Best forLegacy systems, wide compatibilityNew systems, maximum securityRegulated environments (FIPS)

When to Choose Each

Choose Argon2id when...
  • Starting a new system or greenfield project
  • Your language or framework supports it natively (Python passlib, PHP password_hash, Rust argon2, Go argon2)
  • Users may have long passphrases or passwords exceeding 72 characters
  • Maximum resistance to hardware-accelerated cracking is a priority
  • FIPS compliance is not required
Choose bcrypt when...
  • Argon2 is not available in your language or framework
  • Maintaining an existing bcrypt deployment that is correctly tuned
  • You need a battle-tested, universally understood solution (Node.js, Ruby, PHP, etc.)
  • Passwords are enforced to be under 72 bytes (most standard login flows)
Choose PBKDF2 when...
  • FIPS 140-2 or government compliance requires it
  • Operating in regulated industries (finance, US federal systems, healthcare with specific mandates)
  • Your compliance auditors explicitly require a NIST-certified KDF
  • You tune iterations aggressively (600,000+ for PBKDF2-SHA256) and accept the GPU-attack tradeoff

If you are starting fresh today

The combination of OWASP guidance, Password Hashing Competition results, and NIST SP 800-63B all point to Argon2id as the modern default. When in doubt, choose Argon2id.

Parameter Guidance

OWASP-recommended configurations as of 2026. Tune to achieve 200–500ms hash time on your production hardware — increase parameters as hardware improves.

bcrypt

Minimum

cost = 10

Recommended

cost = 12

Each increment doubles work. Aim for ~300ms. Test on your server hardware — not developer laptop.

Argon2id

Minimum (OWASP)

m=19456, t=2, p=1

Higher security

m=65536, t=3, p=4

m = memory in KiB, t = iterations, p = parallelism threads. Balance server RAM against security.

PBKDF2

SHA-256 (recommended)

iterations = 600,000

SHA-512

iterations = 210,000

Higher iteration counts increase resistance to GPU attacks. Use a salt of at least 128 bits.

Benchmark on your production hardware

These are starting points. Run a benchmark loop on the actual server that will handle logins. The goal is 200–500ms per hash — slow enough to deter attackers, fast enough for users. As hardware improves each year, increase your parameters.

Migration Considerations

Moving between password hashing algorithms does not require a forced password reset. Use lazy migration — upgrade hashes on each successful login.

bcrypt → Argon2id

Most straightforward migration. Store an algorithm identifier (or detect format from the hash prefix:$2b$ for bcrypt, $argon2id$ for Argon2).

On login: verify with the old algorithm, then re-hash and store with Argon2id. Over time, active users are migrated automatically.

PBKDF2 → Argon2id

Same lazy migration pattern. Tag each stored hash with its algorithm and parameters so your verification logic knows which function to use.

Consider wrapping — hash the PBKDF2 output with Argon2id on first login to upgrade the entire hash database incrementally.

Upgrading cost / iterations

Even staying on the same algorithm, you should increase parameters every few years as hardware improves. Use the same lazy migration — verify with the old cost, re-hash with the new cost on success.

Store parameters alongside each hash so old and new hashes can coexist during rollout.

Common Mistakes

X

Using MD5 or SHA-256 instead of a KDF

MD5 and SHA-256 are general-purpose hash functions optimized for speed. On a modern GPU, attackers can test billions of MD5 hashes per second. Purpose-built KDFs (bcrypt, Argon2, PBKDF2) are intentionally slow and are the only appropriate tools for password storage.

X

Setting the cost factor or iterations too low

bcrypt cost 4, PBKDF2 with 1,000 iterations, or Argon2 with 1 MB memory — these are far below recommended minimums. Parameters set in 2010 are inadequate today. Benchmark on production hardware and target 200–500ms hash time.

X

Ignoring bcrypt's 72-byte password limit

bcrypt silently truncates passwords at 72 bytes. If a user sets a 100-character passphrase, only the first 72 bytes are hashed. Two different long passwords can become the same hash. Mitigate by SHA-256-hashing the password before passing to bcrypt, or switch to Argon2.

X

Generating salts manually for bcrypt or Argon2

Both bcrypt and Argon2 auto-generate cryptographically secure salts and embed them in the output hash string. Generating your own salt and passing it in is unnecessary and risks using a weak random source. Use the library defaults.

X

Using PBKDF2 without FIPS requirement

PBKDF2 is not memory-hard, making it significantly cheaper to attack with GPU farms than Argon2. Unless you have a compliance requirement, there is no reason to choose PBKDF2 over Argon2id for new systems.

X

Never updating parameters as hardware improves

Hardware gets faster every year. A bcrypt cost factor of 10 that took 300ms in 2015 may take only 50ms today on newer CPUs. Re-benchmark annually and increase parameters using lazy migration on next login.

Try It Yourself

Generate bcrypt hashes and verify passwords directly in your browser — nothing is uploaded or stored.

Frequently Asked Questions

Related Tools

Related Guides and Comparisons