A GPU rig that costs about $5,000 a month to rent can now try 180 billion SHA-256 guesses a second. Point the same rig at a password stored with Argon2id and it drops to roughly 1,000 guesses a second, a gap of more than 180 million times. That single number is why the password hashing conversation in 2026 has narrowed to two real contenders: Argon2 and bcrypt. Both are designed to be slow on purpose. Both show up in nearly every serious framework’s auth stack. But they were built 16 years apart, they solve the “slow it down” problem in different ways, and picking the wrong one still shows up in breach reports. This comparison walks through the specs, the benchmarks, the real dollar cost of cracking each one, and a migration path if you’re still running bcrypt.
Why Password Hashing Is Under Pressure in 2026
Credential-stuffing tools don’t need to break your encryption. They just need your password hashes and enough compute to guess faster than you can rotate accounts. GPU prices climbed through 2025 and into 2026 as AI training soaked up manufacturing capacity, but rental compute through cloud GPU marketplaces stayed cheap enough that offline cracking remains a budget-line item for attackers, not a research project. A 2025-2026 password hashing benchmark, run on a Xeon E5-2680 and referenced across recent security guidance, found that a fast general-purpose hash like SHA-256 lets an attacker try on the order of 180 billion combinations per second on modern GPU hardware. Slow the function down deliberately, and that number collapses.
That’s the entire premise behind Argon2 and bcrypt. Neither one encrypts a password. Both take a password and a random salt and grind through a deliberately expensive computation so that checking one login takes a fraction of a second for your server, but cracking millions of stolen hashes takes an attacker weeks, months, or years. The question isn’t whether to slow things down. It’s which algorithm slows things down in a way that still holds up against 2026 hardware.
Regulators have started treating this as a compliance question, not just an engineering one. NIST SP 800-63B, the federal digital identity guideline, requires verifiers to store memorized secrets using a suitable one-way key derivation function with a per-user salt, and increasingly points implementers toward memory-hard designs rather than fast, iteration-only hashes. That guidance shapes procurement requirements well beyond government systems, since plenty of enterprise vendors build to the same bar to sell into regulated industries. It’s also why the choice between Argon2 and bcrypt shows up in security questionnaires and vendor audits now, not just engineering design docs.
What Is bcrypt?
bcrypt was published in 1999 by Niels Provos and David Mazières, built on top of the Blowfish cipher’s key schedule. It bakes in a cost factor (also called a work factor) that you set as a power of two, so cost factor 12 means 2^12 rounds of key expansion before the final hash is produced. Raise the cost factor by one and you double the work, which is how bcrypt has stayed relevant as CPUs got faster. OWASP’s current guidance still lists a bcrypt cost factor of at least 10, with many teams running 12 or higher in production.
bcrypt’s biggest limitation isn’t speed, it’s memory. The algorithm uses a fixed, small memory footprint (a few kilobytes), which was a non-issue in 1999 but is a real weakness now. Custom ASICs and GPU clusters are extremely good at running thousands of parallel bcrypt instances at once because each one barely touches RAM. bcrypt also silently truncates input at 72 bytes, a detail that still trips up developers integrating it into new systems, and some early or buggy implementations further truncated the effective input at the first NUL byte.
bcrypt hashes also carry their own versioning scheme baked into the string itself, which is worth understanding before you ever touch a migration script. A stored value like $2b$12$ tells you the variant ($2a, $2b, or $2y depending on the library), the cost factor (12 in this example), and then the salt and hash concatenated together. Different language ports have historically disagreed slightly on how they handle the $2x variant, a legacy compatibility flag tied to a PHP implementation bug fixed years ago. None of that breaks the algorithm, but it means a naive string comparison during a library swap can silently reject valid hashes if a team isn’t careful about which prefixes their new bcrypt library actually accepts.
What Is Argon2?
Argon2 won the Password Hashing Competition (PHC) in July 2015, an open, multi-year contest that evaluated dozens of candidate algorithms against a panel of cryptographers. It was designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich at the University of Luxembourg specifically to close bcrypt’s memory gap. Argon2 ships in three variants: Argon2d (maximizes resistance to GPU cracking, but has some side-channel exposure), Argon2i (optimized to resist side-channel attacks, at some cost to GPU resistance), and Argon2id, a hybrid that most current guidance recommends as the default.
The core idea is memory-hardness. Argon2 forces the machine computing the hash to allocate a large, configurable block of RAM (commonly tens of megabytes per hash, well beyond bcrypt’s few kilobytes) and to read and write across that memory repeatedly. That’s cheap for a single login on a normal server, but brutally expensive for an attacker trying to run millions of parallel guesses, because GPUs and ASICs have comparatively little fast memory per compute core. RFC 9106, published by the IETF in September 2021, formalizes Argon2id as the recommended default and lays out reference parameter sets for different deployment scenarios. The OWASP Password Storage Cheat Sheet lists Argon2id as its first-choice recommendation, ahead of both bcrypt and scrypt.
RFC 9106 actually spells out two distinct parameter sets rather than one, and the difference matters when you’re sizing a deployment. The document’s “first recommended option” calls for Argon2id with a single iteration (t=1), four parallel lanes (p=4), and 2 GiB of memory (m=2^21 KiB), paired with a 128-bit salt and a 256-bit output tag. That’s a heavyweight configuration meant for servers with memory to spare. The “second recommended option,” meant for more constrained environments, drops to three iterations (t=3) at the same four lanes but cuts memory to 64 MiB (m=2^16 KiB), which is the range most of the benchmark figures in this article use. Neither option is “the” Argon2 setting. Which one you pick depends entirely on how much RAM your login path can afford to spend per request, multiplied by your peak concurrent login volume.
The competition that produced Argon2 is still documented at the Password Hashing Competition’s official site, and the reference implementation lives in a public GitHub repository maintained by the original design team, which most language bindings wrap rather than reimplementing the core algorithm from scratch. That matters for auditability. When your Node.js, Python, or Ruby Argon2 library calls down to the same underlying C implementation everyone else uses, a security fix upstream propagates to every ecosystem at once instead of requiring dozens of independent patches.
Argon2 vs bcrypt: Full Specs Comparison
Here’s how the two stack up across the details that actually matter when you’re picking one for a production system.
A few rows deserve extra attention beyond what fits in a table cell. The “tunable parameters” row understates how much control Argon2id gives you over the memory-versus-time tradeoff, since bcrypt’s single cost factor can only make the algorithm slower, never adjust how much RAM it touches. And the “FIPS 140 validated” row applies to both algorithms equally, which surprises teams who assume the newer, more secure option would automatically clear a compliance bar the older one doesn’t. It doesn’t work that way. FIPS validation is a formal certification process, not a security ranking, and neither Argon2 nor bcrypt has gone through it as of 2026.
| Attribute | bcrypt | Argon2 (Argon2id) |
|---|---|---|
| Released | 1999 | 2015 (PHC winner), RFC 9106 in 2021 |
| Designers | Niels Provos, David Mazières | Biryukov, Dinu, Khovratovich (University of Luxembourg) |
| Underlying primitive | Blowfish cipher key schedule | Custom memory-hard function |
| Memory hardness | No (fixed, ~4 KB) | Yes (configurable, commonly 19 MiB+) |
| Tunable parameters | Cost factor only | Memory, iterations, parallelism (3 independent knobs) |
| Max input length | 72 bytes (silent truncation) | No practical limit |
| GPU crack resistance | Moderate | High |
| Side-channel resistance | N/A (not a design goal) | Argon2id balances both attack classes |
| FIPS 140 validated | No | No |
| NIST SP 800-63B status | Acceptable in practice, not named | Meets memory-hard guidance |
| OWASP recommendation rank | 3rd choice | 1st choice |
| Typical hash time (tuned) | ~250 ms at cost=12 | ~250 ms at m=64 MiB, t=3 |
| Language/library support | Extremely broad, mature | Broad, newer bindings still maturing in some ecosystems |
Benchmark Data: Speed, Memory, and Latency
Raw speed numbers only tell half the story with password hashing, since the goal is to be slow for attackers but fast enough that your login page doesn’t stall. A 2025-2026 benchmark run on a Xeon E5-2680 at 2.7 GHz, tuning each algorithm to a comparable ~250 ms hash time, produced these figures.
| Algorithm | Configuration | Time per hash | Memory used |
|---|---|---|---|
| Argon2id | m=64 MiB, t=3, p=1 | ~250 ms | 64 MiB |
| bcrypt | cost=12 | ~250 ms | ~4 KB |
| scrypt | N=2^17 | ~350 ms | 128 MiB |
| PBKDF2-SHA256 | 600,000 iterations | ~200 ms | <1 MB |
The memory column is the entire story. At roughly the same wall-clock cost per login, Argon2id forces 64 MiB of RAM per hash while bcrypt uses about 4 KB, a difference of more than 16,000x. A single consumer GPU has enough compute cores to run tens of thousands of bcrypt attempts in parallel because each one is memory-cheap. Run the same GPU against Argon2id and the available VRAM becomes the bottleneck, not compute, which is exactly the design goal. PBKDF2-SHA256, even tuned to 600,000 iterations as current OWASP and NIST SP 800-132-style guidance recommends, still uses under 1 MB of memory and remains the fastest of the four to crack per dollar of GPU rental.
It also helps to translate “memory used” into what actually sits on the GPU side of a cracking attempt. A modern datacenter GPU carries 40 to 80 GB of high-bandwidth memory. Against bcrypt’s 4 KB footprint, that’s enough headroom to keep hundreds of thousands of parallel hash attempts resident at once. Against Argon2id at 64 MiB per attempt, the same card can only hold a few hundred to a couple thousand attempts in memory simultaneously, and every attempt still has to walk through that memory block sequentially rather than just streaming through a compute pipeline. The gap isn’t just about raw hash-per-second throughput. It’s about how many parallel guesses physically fit on the silicon at the same time.
The Real Cost of Cracking: GPU Economics Compared
Benchmark milliseconds are abstract. Dollar figures aren’t. A 2025-2026 cloud-cracking cost model estimated the time and rented-GPU spend needed to brute-force a single 8-character complex password (mixed case, numbers, symbols) against each algorithm at the configurations above.
| Algorithm | Estimated crack time | Estimated GPU rental cost |
|---|---|---|
| PBKDF2-SHA256 (600k iterations) | ~3 days | ~$5,000 |
| bcrypt (cost=12) | ~30 days | ~$40,000 |
| scrypt (N=2^17) | ~200 days | ~$300,000 |
| Argon2id (128 MiB, t=3) | ~500 days | ~$750,000 |
That’s roughly a 19x cost gap between bcrypt and Argon2id for cracking the same password class, and a 150x gap between the weakest and strongest option in the table. It also explains a separate 2026 empirical study that modeled credential-stuffing and offline attacks against real-world password data: switching from SHA-256-based hashing to an RFC 9106-style Argon2 configuration with 2048 MiB of memory cut account compromise rates by about 46.99% at a $20 attacker budget. Budget matters here. Raise the memory parameter and you push the crack cost up further, but you also raise your own server’s RAM bill per login, which is the real tradeoff every team has to make.
Current GPU rental market rates give a sense of how those crack-time estimates translate into an actual attacker budget. 2026 pricing snapshots put on-demand H100 instances at roughly $1.50 to $6.88 an hour depending on the provider and commitment level, with spot and marketplace pricing on platforms like Vast.ai running closer to $2.21 an hour for verified datacenter H100 hosts and as low as $0.35 to $1.32 an hour for A100 80GB cards on the open marketplace. At the low end of that range, the $750,000 Argon2id crack estimate from the table above works out to renting a meaningful GPU fleet continuously for well over a year. At the low end of the bcrypt estimate, $40,000 buys that same fleet for roughly a month. The dollar figures move with the GPU market, but the multiple between algorithms doesn’t, which is the more durable number to plan around.
Why SHA-256 and BLAKE3 Fail as Password Hashes
It’s worth being explicit about why fast general-purpose hashes stay off this list entirely, because the mistake still shows up in new codebases. SHA-256 is a cryptographically strong hash for verifying file integrity or signing data, and BLAKE3 is even faster, hitting roughly 13,196 MB/s on a 1 MB input on modern AMD EPYC hardware in 2025 benchmarks, against about 2,373 MB/s for SHA-256 on the same platform. That speed is a feature for file hashing and content-addressed storage, where you want to hash gigabytes quickly. For passwords, that exact property is the vulnerability. A hash function optimized to process data as fast as possible is also optimized to let an attacker guess passwords as fast as possible.
Neither SHA-256 nor BLAKE3 was designed to be slow, memory-hard, or resistant to parallel GPU attack. Storing raw or lightly-iterated SHA-256 password hashes is why the 180-billion-guess-per-second figure from earlier in this piece is even possible. If your team is choosing a hash for password storage, the entire SHA family and BLAKE3 belong in the “not for this job” column, full stop, regardless of how fast or well-audited they are for other purposes.
This distinction gets confused because SHA-256 and SHA-3 (standardized under FIPS 202, which NIST decided to update in March 2025) are genuinely excellent algorithms for what they were built to do: verifying that a file hasn’t been tampered with, signing data, or building the internal structure of a blockchain. NIST maintains its own hash function policy page tracking exactly which algorithms are approved for which use cases, and password storage was never one of the listed use cases for a raw SHA hash. The failure mode isn’t a broken algorithm, it’s a mismatched one. Speed is the correct optimization target for a Git commit hash. It’s the wrong optimization target for the one field in your database that gates access to every other field.
Security Track Record and Known Weaknesses
bcrypt has run in production for over 25 years without a practical break of its core algorithm. Its weaknesses are implementation-level rather than cryptographic: the 72-byte truncation, older buggy ports that truncated at a NUL byte, and version prefix confusion between $2a$, $2b$, $2x$, and $2y$ hashes across different library ports. None of these amount to a broken primitive, but they’re the kind of detail that causes real incidents when a migration or a library swap gets it wrong.
Argon2’s weaknesses are mostly about deployment maturity rather than cryptanalysis. Argon2d and the pure GPU-optimized path are more exposed to side-channel timing attacks, which is why Argon2id, the hybrid, is the near-universal recommendation now. Because Argon2 is memory-hard, misconfigured servers running many concurrent Argon2id verifications under high login traffic (think a credential-stuffing spike, not just normal usage) can hit real memory-exhaustion problems, effectively a self-inflicted denial-of-service risk if the memory parameter isn’t sized against your server’s actual RAM budget and concurrency limits.
Neither algorithm protects a genuinely weak password. A memory-hard, GPU-resistant function still hashes “password123” in under a second, and a dictionary or credential-stuffing attack that already guesses the plaintext correctly doesn’t care how expensive the hash was to compute. Argon2 and bcrypt both raise the cost of brute-forcing the entire keyspace. They don’t substitute for basic password hygiene, rate limiting on login attempts, or checking new passwords against known-breached password lists at signup. Treating the hashing algorithm as the whole defense, rather than one layer of it, is its own kind of misconfiguration.
Real-World Adoption: Who Uses What
Both algorithms show up across major frameworks, but the direction of travel is toward Argon2id as the default recommendation. What’s changed between 2015 and 2026 isn’t a sudden weakness discovered in bcrypt. It’s that enough time has passed for Argon2 to move from “the competition winner” to “the thing every major framework’s documentation now points to,” which is the slow, unglamorous way cryptographic defaults actually shift in practice.
- OWASP: the Password Storage Cheat Sheet ranks Argon2id as its first-choice algorithm, with bcrypt and scrypt listed as acceptable fallbacks.
- Ruby on Rails: the built-in
has_secure_passwordmodule hashes credentials with bcrypt by default, and it remains the standard choice across most Rails apps in production today. - PHP: the native
password_hash()function defaults to bcrypt but has supportedPASSWORD_ARGON2Isince PHP 7.2 (2017) andPASSWORD_ARGON2IDsince PHP 7.3 (2018), which flows through to CMS platforms built on PHP. - Django: the framework’s auth system supports an
Argon2PasswordHasher, and Django’s own documentation recommends installing theargon2-cffipackage and making it the preferred hasher for new projects. - Password Hashing Competition panel: the 2015 selection of Argon2 over 23 other submitted algorithms, including strong contenders from established cryptographers, remains the closest thing the field has to a formal, peer-reviewed endorsement.
The pattern across all five is consistent: frameworks that predate 2015 shipped with bcrypt as the sane, available default of their era, and every framework or guideline written or substantially updated since has pointed new projects toward Argon2id instead. That’s not a knock on bcrypt so much as a reflection of when each piece of software was designed. A framework built in 2005 couldn’t have shipped an algorithm that didn’t exist yet.
Argon2 vs bcrypt vs scrypt vs PBKDF2
Argon2 and bcrypt don’t exist in a vacuum. scrypt, published by Colin Percival in 2009, was the first widely-adopted memory-hard function and predates Argon2 by six years, but its parameter tuning is less flexible and it never went through a competition process. PBKDF2, standardized decades earlier and still the only option sanctioned for FIPS 140-validated federal systems (per current NIST SP 800-131A-style guidance), uses effectively no meaningful memory hardness at all and leans entirely on iteration count to slow attackers down, which is why 2026 recommendations push its iteration count as high as 600,000 for SHA-256.
The practical hierarchy most current guidance settles on: Argon2id first when you control the full stack, scrypt as a reasonable second if Argon2 bindings aren’t available for your language, bcrypt as a mature and battle-tested fallback with a real memory-hardness gap, and PBKDF2 only when a compliance requirement, like FIPS validation, rules the other three out entirely.
It’s worth noting scrypt isn’t obsolete either. It shows up heavily in cryptocurrency mining and wallet key derivation, where its memory-hardness was borrowed directly from the password-hashing world and repurposed to resist ASIC mining farms. If your team already has scrypt deep in a system for that kind of reason, there’s no urgent case to rip it out purely because Argon2 ranks one slot higher on OWASP’s list. The ranking reflects a slight edge from a newer, more thoroughly reviewed design, not a security emergency in scrypt itself.
5 Use Cases: Which Algorithm to Pick
The right answer changes depending on what you’re actually building.
- New web application, standard user login: Argon2id with RFC 9106-recommended parameters. There’s no legacy constraint holding you back, so start with the strongest default.
- Legacy Rails or PHP app already running bcrypt: keep bcrypt in place short term rather than a rushed rip-and-replace, but plan a lazy migration to Argon2id (detailed below) rather than leaving it indefinitely.
- FIPS 140-validated government or regulated system: PBKDF2-HMAC-SHA256 with a high iteration count, since neither bcrypt nor Argon2 currently holds FIPS validation.
- Resource-constrained embedded or IoT auth: bcrypt, or a deliberately low-memory Argon2id configuration, since full memory-hard parameters may not fit the device’s available RAM.
- High-concurrency API with shared multi-tenant hosting: a carefully sized Argon2id memory parameter, load-tested against real concurrent login volume, to avoid a self-inflicted memory squeeze during traffic spikes.
- Internal admin tools or B2B SaaS with a small, known user base: Argon2id at the heavier RFC 9106 first-recommended setting (2 GiB, t=1), since login volume is low and the extra memory cost per request is easy to absorb for the security margin it buys.
None of these six scenarios are permanent. A resource-constrained IoT device today might ship with more RAM next generation, at which point the “use bcrypt” answer flips to a tuned Argon2id configuration. Revisit the decision when your infrastructure changes, not just when a security review forces the question. Write the reasoning down wherever your team keeps architecture decisions, so the next engineer who touches auth code understands why a particular algorithm and parameter set was chosen instead of re-litigating the choice from scratch.
Migration Guide: Moving From bcrypt to Argon2
Rehashing every stored password at once isn’t possible, since you only ever see a plaintext password at the moment a user logs in. The standard approach is a lazy migration that upgrades hashes gradually as real users authenticate. Expect the full transition to take months, not days, since it depends on how often your user base actually logs back in.
- Add a maintained Argon2 binding to your project (the
argon2npm package for Node.js,argon2-cffifor Python, or theargon2idgem for Ruby). - On login, detect which algorithm produced the stored hash by reading its prefix ($2a$, $2b$, or $2y$ for bcrypt, $argon2id$ for Argon2).
- Verify the submitted password against the existing algorithm first, so current users aren’t locked out mid-migration.
- If verification succeeds against the old bcrypt hash, immediately rehash the plaintext password with Argon2id and overwrite the stored value.
- Set your Argon2id parameters per RFC 9106 guidance, then load-test them against your actual concurrent login volume before rolling out to production.
- For accounts that haven’t logged in for an extended period, consider a forced password reset rather than waiting indefinitely for a lazy rehash.
- Monitor server memory and CPU after rollout, since Argon2id’s memory-hard design means your infrastructure cost per login goes up, not just your security margin.
const argon2 = require('argon2');
const bcrypt = require('bcryptjs');
async function verifyAndUpgrade(user, submittedPassword) {
const storedHash = user.passwordHash;
if (storedHash.startsWith('$argon2id$')) {
return argon2.verify(storedHash, submittedPassword);
}
// Legacy bcrypt hash: verify, then lazily upgrade to Argon2id
const bcryptValid = await bcrypt.compare(submittedPassword, storedHash);
if (bcryptValid) {
const newHash = await argon2.hash(submittedPassword, {
type: argon2.argon2id,
memoryCost: 19456, // 19 MiB, RFC 9106 minimum recommendation
timeCost: 2,
parallelism: 1,
});
user.passwordHash = newHash;
await user.save();
return true;
}
return false;
}
The same lazy-migration pattern applies outside Node.js. A Python app on Django can wrap this logic in a custom authentication backend and lean on argon2-cffi for the new hashes. A PHP app can call the built-in password_needs_rehash() function, which was specifically added to make this exact upgrade path a one-line check rather than a custom implementation. The mechanics differ by language, but the sequence is identical everywhere: verify against the old algorithm, rehash with the new one on success, overwrite the stored value.
One detail teams miss: don’t just swap the verification library and call it done. Log which algorithm each successful login used, even temporarily, so you can track migration progress and see the shrinking tail of accounts still on bcrypt. That tail is exactly where you’ll want to eventually apply the forced password reset from step six, rather than guessing at when “most” users have migrated.
Roll this out behind a feature flag if your deployment pipeline supports one, and ship it to a small percentage of traffic first. The failure mode to watch for isn’t a security bug, it’s a latency regression: if your Argon2id parameters are tuned too aggressively for your server’s actual CPU and memory budget, login requests queue up under load in a way a small canary rollout will surface long before a full production deploy does.
Pros and Cons
Laid out side by side, neither algorithm is a bad choice in absolute terms. Both beat the far more common mistake of using a fast general-purpose hash or, worse, storing passwords with reversible encryption instead of a one-way hash at all. The comparison here is a question of how much more security margin Argon2id buys you and whether that margin is worth the migration effort for your specific system.
Argon2id
Pros: memory-hard design that closes the GPU-parallelism gap bcrypt leaves open, tunable across three independent parameters, formally standardized in RFC 9106, and the top recommendation from OWASP. Cracking costs run roughly 19x higher than bcrypt for equivalent hash-time settings.
Cons: newer than bcrypt, so some older language ecosystems have less mature bindings. Memory-hard by design means real RAM cost on your servers, and misconfigured parallelism or memory settings under heavy login traffic can create availability problems. Not FIPS 140-validated.
bcrypt
Pros: more than 25 years in production with no practical cryptographic break, extremely broad and mature library support across essentially every language, simple single-parameter tuning, and a small, predictable memory footprint that’s easy to capacity-plan around.
Cons: no memory-hardness, which leaves it more exposed to large-scale parallel GPU cracking than Argon2id at comparable hash times. The 72-byte input truncation is a real footgun for teams that don’t know about it. OWASP now ranks it behind both Argon2id and scrypt.
The Verdict for 2026
Argon2id wins on the numbers. It costs an estimated 19x more in GPU rental to crack the same password class as bcrypt, it cut real-world account compromise rates by close to 47% against a fast-hash baseline in 2026 research, and it carries the direct endorsement of both the Password Hashing Competition and OWASP’s current guidance. If you’re starting a new project today, there’s no real argument for reaching past Argon2id.
That doesn’t make bcrypt obsolete. A quarter-century of production use without a cryptographic break is a track record Argon2 hasn’t had time to build yet, and bcrypt’s predictable, low memory footprint still matters for resource-constrained systems or teams that can’t yet justify a migration project. The realistic guidance for most teams running bcrypt today: don’t panic, don’t rip it out overnight, but start the lazy migration to Argon2id described above, and set a deadline for the accounts that never log back in.
The one group that shouldn’t default to either: anyone under FIPS 140 validation requirements, who still needs PBKDF2 regardless of what the rest of this article recommends. Check your compliance obligations before your technical preference. A cryptographically superior algorithm that fails an audit doesn’t help you ship.
Whichever algorithm your team lands on, the underlying lesson holds either way: password hashing is a parameter-tuning problem that needs revisiting as hardware improves, not a set-once library import. The cost factor that felt slow in 2020 is fast today, and the memory setting that feels generous in 2026 will feel thin in a few years as GPU memory bandwidth keeps climbing. Put a recurring review of your hashing parameters on the same calendar as your dependency updates, not filed away as a decision you made once and never revisit.
Frequently Asked Questions
Is bcrypt broken or unsafe to use in 2026?
No. bcrypt’s core algorithm has no known practical cryptographic break. It’s considered weaker than Argon2id specifically because it lacks memory-hardness, not because it’s been compromised.
Which Argon2 variant should I use, Argon2i, Argon2d, or Argon2id?
Argon2id for password hashing, in almost every case. It’s the hybrid RFC 9106 recommends as the default, balancing GPU resistance with side-channel resistance.
Is Argon2 FIPS 140 validated?
No, and neither is bcrypt. Teams under FIPS 140 compliance requirements currently need to use PBKDF2 with an approved HMAC construction instead.
Why can’t I just use SHA-256 for passwords?
Because it’s fast, and fast is the opposite of what you want for password storage. Modern GPUs can attempt roughly 180 billion SHA-256 guesses per second, which makes raw or lightly-iterated SHA-256 password hashes trivial to crack at scale.
What’s the difference between Argon2 and scrypt?
Both are memory-hard, but scrypt predates Argon2 by six years and offers less flexible parameter tuning. Argon2 went through a formal, multi-year public competition process that scrypt never did, which is part of why OWASP now ranks Argon2id above it.
Does bcrypt really truncate passwords at 72 characters?
Yes. bcrypt silently ignores any input beyond 72 bytes, and some older or buggy ports truncate even earlier, at the first NUL byte. This has caused real security issues when developers weren’t aware of the limit.
How do I migrate existing bcrypt hashes to Argon2 without forcing a password reset?
Use a lazy migration: verify against the existing bcrypt hash at login, and if it succeeds, immediately rehash the plaintext password with Argon2id and store the new hash. Users who don’t log back in for a set period can be handled with a forced reset instead.
Can Argon2’s memory usage cause performance problems on my server?
It can, if the memory parameter isn’t sized against your actual concurrent login volume. A sudden traffic spike, like a credential-stuffing attempt, running thousands of simultaneous Argon2id verifications at 64 MiB each can exhaust server RAM. Load-test your configuration before rolling it out.
Do I need to add my own salt when using Argon2 or bcrypt?
No. Both algorithms generate a random salt automatically and embed it directly in the output string, so every stored hash already contains everything needed to verify a future login. Adding a second, manually-managed salt on top doesn’t meaningfully improve security and just adds a place for implementation bugs to creep in.
Should I use bcrypt for a brand-new project in 2026?
Generally, no. If you’re not constrained by an existing codebase, framework default, or FIPS requirement, Argon2id gives you a meaningfully wider security margin against modern GPU cracking for a similar implementation effort. Reach for bcrypt when a specific technical or compliance constraint rules Argon2id out, not as a default first choice.
Related Coverage
- Argon2 Password Hashing in Node.js: 11 Steps [2026]
- bcrypt Password Hashing in Node.js: 11 Steps [2026]
- SHA-256 vs SHA3-256: 3.5x Speed Gap, Same 128-bit Security [2026]
- Hashing vs Encryption: Fixed 256-Bit Output, No Key [2026]
- Passkeys vs Passwords: 8.5s vs 31s Sign-In [2026]
- More Cryptography Coverage



