·5 min read

Argon2 vs bcrypt vs scrypt: picking a password hash in 2026

A practical comparison of the three modern password-hashing functions, with sensible cost parameters and where each one falls short.

If you're storing passwords, you do not use SHA-256. You don't use MD5 either, salted or not. You use a password hashing function — one specifically designed to be slow and memory-hungry, so an attacker who steals your database can't grind through billions of guesses per second on a GPU.

There are three serious choices in 2026. This post walks through each one, when to pick it, and what cost parameters to use.

Why a regular hash is the wrong tool

A fast hash like SHA-256 was designed for integrity checking. On a modern GPU you can compute hundreds of billions of SHA-256 hashes per second. That is exactly the speed you don't want for passwords, because an attacker who steals your users table will use that same GPU to try every common password — and most password lists fit in a few gigabytes.

A password hash is deliberately slow. Even a modest setting — 50 ms per hash — drops an attacker from ~10¹¹ guesses per second to ~20 guesses per second per GPU core. That's the entire game.

Salting alone doesn't fix it. A salt forces the attacker to crack each password separately instead of building one rainbow table — but if each guess takes 10 microseconds, the attacker still gets through a 10,000-word list in milliseconds per user. Slowness is the missing ingredient.

The three serious choices

Function Year Memory-hard? Standardized as Where you'll find it
bcrypt 1999 No De facto Rails, PHP, Node, Go, ~every web framework
scrypt 2009 Yes RFC 7914 Some crypto wallets, Lightning, libsodium
Argon2id 2015 Yes RFC 9106 OWASP-recommended default; libsodium

All three salt automatically, all three encode the salt and cost parameters into the output hash string, and all three are slow by design. The difference is in how they're slow.

bcrypt: the default that still works

bcrypt has one tunable parameter — cost (also called work factor). Each increment doubles the time to hash. In 2026, a cost factor of 12 takes about 200 ms on a typical server core. Cost 13 takes 400 ms. Cost 14 takes 800 ms. Pick the highest cost your login latency budget can absorb.

What bcrypt does not do is memory-hard. It uses about 4 KB of memory per hash. An attacker with a GPU farm or an FPGA cluster can parallelize the attack hard. That said, in 2026 bcrypt at cost 12+ is still tens of dollars of compute per cracked password for anything except top-50 common passwords — which you should be rejecting on signup anyway.

Use bcrypt when:

  • Your runtime has a battle-tested library and you don't want to take chances with the bindings.
  • Your threat model is "someone stole the DB, not a state actor."
  • You don't want to think about it.

Most authentication libraries in most languages default to bcrypt. Leaving the default at cost 10 in 2026 is too low; bump to 12.

scrypt: memory-hard, but Argon2 is usually better

scrypt was the first widely-deployed memory-hard function. It uses memory in a way that makes specialized hardware (GPU, FPGA, ASIC) much less effective per dollar than for bcrypt. A typical scrypt parameter set in 2026 uses 16 MB of memory per hash.

scrypt is still good. The reason most new code uses Argon2 instead is that Argon2 has a wider tunable parameter space, won a multi-year competition, and is the recommendation of OWASP, the IETF (RFC 9106), and basically every security guide written after 2017.

Use scrypt when:

  • You're integrating with an existing system that already uses it (Lightning wallets, some crypto exchanges).
  • libsodium is your crypto library and you're more comfortable with its scrypt API than its Argon2 API.

For greenfield work, Argon2 is the better default.

Argon2id: the modern default

Argon2 won the Password Hashing Competition in 2015. It has three variants:

  • Argon2d — maximizes resistance to GPU attacks. Susceptible to side-channel attacks. Don't use this for passwords.
  • Argon2i — side-channel-resistant. Slightly weaker against GPU attacks.
  • Argon2id — hybrid. Side-channel-resistant in the first half, GPU-resistant in the second. Use this one.

Argon2id has three tunable parameters:

  • Memory cost (m) — RAM used per hash, in KB.
  • Time cost (t) — number of iterations.
  • Parallelism (p) — how many threads can compute in parallel.

OWASP's 2024 recommendations (still current):

  • Sensitive server-side use: m = 47104 (≈46 MB), t = 1, p = 1.
  • Lower-memory environment: m = 19456 (≈19 MB), t = 2, p = 1.

A single hash takes 50–200 ms on a typical server core with these parameters. An attacker with a 24 GB GPU can run maybe 500 parallel hashes at the high setting — vs. millions of bcrypt hashes on the same hardware. That memory ceiling is what makes Argon2 expensive to attack at scale.

Use Argon2id when:

  • You're picking from scratch in 2026.
  • Your runtime has a maintained binding (Rust, Go, Node, Python, Java, .NET all do).
  • You want a function that will still be the recommendation in 2030.

Cost parameters: how to pick

The honest rule: pick the highest cost that keeps your p99 login latency under 250 ms on your real production hardware. Measure, don't guess. Login is the only operation that hits the password hash; once-per-session is fine to spend a quarter of a second on.

For most webapps in 2026:

  • bcrypt cost 12 if you have to use bcrypt.
  • Argon2id at OWASP defaults (m=47104, t=1, p=1) if you can pick fresh.

Re-measure once a year. CPUs get faster; bump cost when you can.

Pepper, key stretching, and other variations

A pepper is a secret value mixed into every password before hashing, stored outside the database. If the DB leaks but the pepper doesn't, an attacker can't crack the passwords offline. Useful in some threat models; complicates rotation. If you're not already running with a pepper, adding one to an existing system is non-trivial — you need a migration plan.

Don't roll your own variation. Don't double-hash ("bcrypt(sha256(password))" is a real anti-pattern — pre-hashing with SHA-256 can leak through bcrypt's 72-byte input truncation and create equivalence classes). Use the library function as published.

What this site does (and doesn't)

The Hash Generator on this site supports MD5, SHA-1, SHA-256, SHA-512 — fast hashes for integrity, not passwords. It deliberately does not implement Argon2 or bcrypt because client-side password hashing is rarely what you actually want: the server can't verify a hash it didn't compute, so the hash becomes the password from the server's perspective. Real password hashing happens server-side, against a stolen DB threat model.

What you can do here is generate a strong password to hash. The Password Generator uses your browser's CSPRNG to produce passwords with measurable entropy. Pair that with Argon2id on your server, and you've solved the password-storage problem for 2026.

The shortest possible answer

  • New code in 2026: Argon2id at OWASP defaults.
  • Existing bcrypt deployment: keep it, but bump cost to 12 or higher.
  • Existing scrypt deployment: keep it.
  • For everything else (file integrity, cache keys, signatures): SHA-256, not a password hash.

Related tools

Password GeneratorGenerate strong, random passwords in your browser. Choose length, character types, exclude lookalikes. Nothing is sent to any server.Hash Generator (MD5, SHA-256…)Generate MD5, SHA-1, SHA-256, SHA-384, and SHA-512 hashes from text in your browser. Verify checksums without leaking the input.UUID GeneratorGenerate cryptographically random UUIDs (v4) in your browser. Bulk-generate, copy one, or copy all. Nothing leaves your device.
← All posts