Password hashing rarely makes headlines, but it quietly decides how expensive a breach becomes. When a database of hashed passwords leaks, the algorithm behind those hashes determines whether attackers crack them in an afternoon or spend decades of GPU time trying. Two algorithms, scrypt and bcrypt, have handled that job for well over a decade, and engineers still argue about which one to pick when Argon2id, the current OWASP favorite, is not an option. This comparison breaks down how scrypt and bcrypt actually work, what current benchmarks say about cracking speed, what OWASP’s October 2026 guidance recommends, and which one fits specific deployment scenarios.

The short version: scrypt leans on memory, forcing an attacker to buy expensive RAM-heavy hardware instead of cheap GPU cycles. bcrypt leans on raw CPU repetition through a modified Blowfish cipher, which keeps it fast, compact, and easy to deploy, but also easier to accelerate with consumer graphics cards. Neither is broken. Both remain acceptable under current OWASP Password Storage Cheat Sheet guidance, just in a specific order of preference.

What Is bcrypt and Where Did It Come From?

bcrypt dates back to 1999, when Niels Provos and David Mazières published “A Future-Adaptable Password Scheme” at the USENIX Annual Technical Conference. The goal was straightforward: build a password hash that could get slower over time as hardware got faster, without forcing a rewrite of the underlying algorithm. Their answer was EksBlowfish, an expensive key-scheduling variant of the Blowfish cipher that repeatedly folds the password and a random salt into the cipher’s internal state before encrypting a fixed string 64 times.

The tunable piece of bcrypt is a single cost factor, an integer typically between 4 and 31 that sets the work factor to 2 raised to that power. Bump the cost from 11 to 12 and you roughly double the computation required, both for a legitimate login check and for an attacker guessing passwords offline. That simplicity is bcrypt’s biggest selling point. There is one knob to turn, the output fits in a compact 184-bit encoded string, and virtually every mainstream language has a mature, audited bcrypt library.

bcrypt’s output format usually starts with a version tag such as $2b$, followed by the cost factor and a base64-encoded 128-bit salt. That compactness made bcrypt a natural fit for relational databases in the early 2000s, and it never really lost that foothold. Twenty-seven years after Provos and Mazières published their paper, bcrypt is still the default password hasher behind countless login forms.

What Is scrypt and Why Memory Matters?

scrypt came a decade later, built for a very different threat model. Colin Percival designed it for Tarsnap, his own online backup service, and described the construction in a 2009 paper titled “Stronger Key Derivation via Sequential Memory-Hard Functions.” The IETF eventually standardized the design as RFC 7914 in 2016, giving scrypt a formal specification that bcrypt never received.

Percival’s insight was that CPU speed was getting cheap relative to the cost of specialized cracking hardware, but memory bandwidth and capacity were not scaling nearly as fast. So instead of just repeating a cipher many times, scrypt builds a large pseudorandom block of data in memory and then reads it back in an unpredictable order. That pattern, called ROMix, wraps around BlockMix, which in turn relies on the Salsa20/8 stream cipher. The initial and final steps use PBKDF2-HMAC-SHA-256 to stretch the password into the right shape before and after the memory-heavy middle stage.

Three parameters control scrypt’s cost: N, the CPU/memory cost expressed as a power of two, r, the block size multiplier, and p, the parallelization factor. Memory consumption follows a simple formula, roughly 128 × N × r bytes. At the OWASP-recommended minimum of N=2^17 and r=8, that works out to about 128 MiB per single password check, before any implementation overhead. Compare that to bcrypt’s internal state, which fits in a few kilobytes, and the design philosophy gap becomes obvious. scrypt wants an attacker to need racks of RAM. bcrypt just wants them to need time.

How the Two Algorithms Actually Differ Under the Hood

bcrypt’s EksBlowfish pipeline

EksBlowfish, short for “expensive key schedule Blowfish,” runs through a specific loop: initialize the Blowfish state with fixed constants, expand it once with the salt and password, then repeat an expansion step using just the salt and password 2^cost times. Once that loop finishes, the resulting state encrypts a fixed 64-bit string, traditionally “OrpheanBeholderScryDoubt,” 64 times to produce the final hash. Every step is deterministic integer arithmetic on a small table, which is exactly the kind of workload a GPU core handles extremely well. Thousands of GPU cores can each run an independent EksBlowfish schedule in parallel with almost no memory contention between them.

scrypt’s ROMix memory wall

scrypt’s ROMix step generates N blocks sequentially, storing every one of them, then reads blocks back in a data-dependent order determined by earlier output. That read pattern is intentionally unpredictable, which means an attacker’s hardware either stores the entire N-block array for every password guess in flight or recomputes blocks on demand and pays a heavy time penalty instead. A GPU with thousands of cores but a shared, comparatively limited memory bus runs into a bottleneck that bcrypt never creates. This is why specialized scrypt cracking hardware looks more like a custom memory controller design than a simple arithmetic accelerator, and why building one is a much bigger engineering and capital commitment than spinning up another bcrypt kernel.

A Brief History: Why Neither Won the Password Hashing Competition

Both algorithms predate one of the more consequential events in applied cryptography: the Password Hashing Competition, an open, multi-year contest organized to find a successor to aging schemes like PBKDF2 and bcrypt. scrypt, already seven years old by the time the competition wrapped up in 2015, was treated as the benchmark the newer submissions had to beat on memory-hardness, not as a contestant competing for the win. bcrypt, by then sixteen years old, was in a similar position: still widely deployed, still considered adequate, but no longer the frontier of password-hashing research.

Argon2 won that competition, and Argon2id specifically has since become the variant OWASP recommends first. It borrows the memory-hard philosophy scrypt pioneered but adds explicit resistance to side-channel timing attacks and GPU-specific optimizations that scrypt’s original 2009 design never had to consider, because the GPU cracking ecosystem of 2009 looked nothing like the one GPU vendors ship today. That is the real reason scrypt and bcrypt both rank below Argon2id in current guidance: not because either algorithm has been broken, but because the state of the art moved on and neither one was built with 2020s-era attack tooling in mind.

This history matters for a practical reason. Teams sometimes assume that because scrypt is “memory-hard” and bcrypt is “just CPU-hard,” scrypt must be the unambiguously modern choice and bcrypt the legacy one to replace at the first opportunity. The more accurate framing is that both are mid-2000s-to-2010s era designs, and the real upgrade path for most new systems runs past both of them, straight to Argon2id. scrypt only outranks bcrypt as a second-choice fallback, not as a first-choice replacement for a genuinely modern setup.

Salting and Rainbow Table Resistance: What Both Algorithms Get Right

It’s worth pausing on what scrypt and bcrypt agree on, because the areas of agreement are just as important as where they diverge. Both algorithms require a unique, randomly generated salt for every password, typically 128 bits in length, and both embed that salt directly in the stored hash output so verification never depends on a separate lookup table. That single design choice is what makes rainbow table attacks, precomputed tables of hash-to-password mappings that worked devastatingly well against unsalted MD5 or SHA-1 password stores, effectively useless against either algorithm. An attacker cannot precompute a universal table covering every possible salt value in advance; the salt space is simply too large.

Both algorithms are also deliberately slow by design, in direct contrast to general-purpose hash functions like SHA-256, which are built to be as fast as possible for legitimate uses like file integrity checks and are consequently terrible choices for password storage. A GPU running 22 billion SHA-256 operations per second, a figure reported from recent hashcat benchmarking, makes brute-forcing an unsalted or weakly hashed password list almost trivial. Neither scrypt nor bcrypt can be accelerated anywhere near that level, which is the entire reason dedicated password-hashing functions exist as a separate category from general-purpose cryptographic hashes in the first place, a distinction covered in more depth later in this piece.

scrypt vs bcrypt: Full Specs Comparison

The table below lines up the two algorithms across the properties that matter for a real deployment decision, from governing standard to practical password-length limits.

Propertyscryptbcrypt
Creator(s)Colin PercivalNiels Provos and David Mazières
Introduced2009 (Tarsnap paper)1999 (USENIX paper)
Formal standardRFC 7914 (2016)No IETF RFC; de facto spec from the original paper
Underlying primitivePBKDF2-HMAC-SHA-256, Salsa20/8, ROMixEksBlowfish (modified Blowfish key schedule)
Design goalMemory-hard key derivationCPU-hard, future-adaptable hashing
Tunable parametersN (cost), r (block size), p (parallelism)Single cost factor (2^cost)
OWASP minimum setting (2026)N=2^17, r=8, p=1Cost factor 10 or higher
Approx. memory use at OWASP minimum~128 MiBA few kilobytes of internal state
Salt size128 bits (RFC 7914 convention)128 bits, base64-encoded in the hash string
Password-length handlingNo fixed truncation defined by the RFCTraditional implementations only process the first 72 bytes
GPU/ASIC resistanceStrong; memory bandwidth bottlenecks parallel attacksWeak to moderate; GPUs parallelize EksBlowfish efficiently
OWASP 2026 preference order2nd choice, after Argon2id3rd choice, after Argon2id and scrypt
Typical output formatRaw derived key, length configurableModular crypt string starting with $2b$
Known real-world use outside passwordsLitecoin proof-of-work miningNone widely adopted outside password/credential hashing

Two rows deserve extra attention. The password-length row matters because applications that silently rely on bcrypt’s 72-byte cutoff can end up treating two different long passwords as identical, which is rarely what a developer intends. The memory row explains almost everything else in this comparison: a hash function that requires 128 MiB per check is fundamentally harder to run a million times in parallel on commodity hardware than one that fits comfortably inside a GPU core’s local cache.

GPU Cracking Benchmarks: What the Numbers Actually Show

Benchmark claims about password hashing get misquoted constantly, usually because the cost factor used in the test gets dropped from the headline. Hashcat’s default bcrypt benchmark mode runs at cost factor 5, a setting nobody should use in production, while real deployments run cost 10 to 13 or higher. With that caveat up front, here is what three independent 2026 benchmark sources report for a single NVIDIA RTX 4090.

Sourcebcrypt (cost 5) speedscrypt speedNotes
cipherdecipher.com~180,000 H/s7,126 H/s at N=16,384scrypt figure is a directly measured result, not an estimate
tutorials.technology~180,000 H/sNot separately benchmarkedExplicitly flags cost 5 as a benchmark default, not a production value
onlinehashcrack.com212,600 H/sNot separately benchmarkedUses hashcat 7.0.0 on an 8x RTX 4090 rig, figure is per-card

The spread between 180,000 and 212,600 hashes per second for bcrypt cost 5 across these sources comes down to driver version, hashcat build, and GPU clock state rather than any disagreement about bcrypt itself. What stays consistent across every source is the relative gap: at comparable “default” settings, scrypt runs roughly 25 times slower per guess than bcrypt. That gap is the entire point of memory-hardness, and it only widens as scrypt’s N parameter climbs toward production-grade values. Scaling the measured N=16,384 result up to OWASP’s recommended N=131,072 (an eightfold increase) produces an estimated 890 hashes per second, a figure the source explicitly labels as an extrapolation rather than a direct benchmark, since public RTX 4090 scrypt results at the full OWASP setting are still sparse.

bcrypt’s own numbers shift dramatically once a realistic cost factor replaces the benchmark default. Because each increment of the cost factor roughly doubles the work, moving from cost 5 to cost 12, the floor recommended by several 2026 security write-ups, cuts throughput by a factor of 128. That turns a 180,000 H/s benchmark number into something closer to 1,400 H/s in production, a figure much closer to scrypt’s own territory. The headline “bcrypt is 25 times faster to crack” is only true when nobody has actually configured bcrypt correctly.

Cost to Crack: What a Cloud GPU Attack Actually Costs

Raw hash rates are hard to picture, so it helps to translate them into dollars using current cloud GPU rental prices. As of October 2026, RunPod’s Community Cloud lists RTX 4090 instances at roughly $0.34 per hour, a mid-range figure among several tracked marketplaces. Using that rate, an exhaustive brute-force search of an 8-character password drawn from lowercase letters and digits (36 characters, roughly 2.82 trillion combinations) on a single rented GPU breaks down like this.

ConfigurationHash rateTime to exhaust keyspaceEstimated cloud GPU cost
bcrypt, cost factor 5 (benchmark default, not production)180,000 H/s~181 days~$1,480
scrypt, N=16,384 (lighter than OWASP minimum)7,126 H/s~12.5 years~$37,390
bcrypt, cost factor 12 (2026 recommended production floor)~1,406 H/s (derived from the cost-5 benchmark)~63.6 years~$189,470
scrypt, N=131,072 (OWASP 2026 minimum, extrapolated)~890 H/s (extrapolated)~100.5 years~$299,370

These figures assume a single rented GPU running a textbook exhaustive search against a random 8-character password, which is already a generous assumption in an attacker’s favor since real password sets usually contain predictable patterns that dictionary and rule-based attacks exploit far faster than brute force. They also ignore the economics of renting hundreds of GPUs in parallel, which proportionally cuts the wall-clock time while keeping the total dollar cost roughly fixed. The point of the table is the relative gap, not an absolute guarantee: at properly configured production settings, both algorithms push a brute-force attack well past the point of being financially rational against a single password, and scrypt’s memory requirement keeps that advantage intact even as GPU rental prices keep falling.

OWASP’s 2026 Password Storage Guidance

The OWASP Password Storage Cheat Sheet, last updated October 5, 2026, lays out a clear preference order: Argon2id first, scrypt second if Argon2id is not available, bcrypt third, and PBKDF2 reserved mainly for environments that need FIPS-140 compliance. For organizations weighing scrypt against bcrypt specifically, that second-versus-third placement is the whole ballgame, and it is driven directly by memory-hardness rather than any flaw in bcrypt’s cryptography.

OWASP’s current minimum settings read as follows. For Argon2id: 19 MiB of memory, two iterations, and a parallelism factor of 1, with higher-memory alternatives such as 47,104 KiB at one iteration also listed. For scrypt: N=2^17, r=8, p=1, the configuration this article uses throughout, alongside lighter alternatives like N=2^14, r=8, p=5 for constrained environments. For bcrypt: a cost factor of 10 or higher, with the explicit instruction to raise it as hardware allows while keeping authentication responsive. Several 2026 industry write-ups push that floor to cost 12 or 13 in practice, treating cost 10 as a bare minimum rather than a target.

Readers who want the full three-way comparison, including where PBKDF2 fits into FIPS-regulated environments, can check the site’s existing breakdown of PBKDF2 vs Argon2 cracking resistance and the separate look at Argon2 vs scrypt memory requirements, both of which cover ground this article does not need to repeat.

Memory-Hardness Explained: Why It Changes the Economics of Attacks

A CPU-hard algorithm like bcrypt makes each guess take longer, but that extra time scales almost linearly with however many parallel cores an attacker throws at the problem. Modern GPUs ship with thousands of cores and relatively small per-core memory needs, which is exactly the shape of workload bcrypt creates. Add more cores, get proportionally more guesses per second, with little else standing in the way.

A memory-hard algorithm like scrypt changes the shape of that problem. Every single guess needs its own roughly 128 MiB block of fast memory at OWASP’s recommended setting. A GPU with 24 GB of VRAM, enough to brute-force bcrypt guesses in the hundreds of thousands per second, can only hold a few hundred scrypt working sets at once, and GPU memory bandwidth, not raw core count, becomes the bottleneck. Building dedicated scrypt-cracking hardware means designing a system optimized for memory throughput rather than arithmetic throughput, a fundamentally more expensive and less flexible engineering problem.

That said, “ASIC-resistant” is a relative claim, not an absolute one. Litecoin’s mining ecosystem, which deliberately chose scrypt as its proof-of-work function specifically to resist specialized SHA-256 hardware, eventually saw dedicated scrypt ASICs appear once the financial incentive from cryptocurrency mining rewards grew large enough. Password cracking and cryptocurrency mining are different economic games, since there is no block reward for cracking a single password hash, but the Litecoin example is a useful reminder that memory-hardness raises the cost of specialized hardware rather than making it permanently impossible.

Real-World Adoption: Where Each Algorithm Actually Runs

Both algorithms have spent decades embedded in production systems, often without the people using them realizing which one is doing the work behind the login form.

  • Litecoin: Launched in 2011, Litecoin’s proof-of-work consensus runs on scrypt, chosen specifically to blunt the advantage that specialized SHA-256 mining hardware already held over Bitcoin miners at the time.
  • Node.js: The built-in crypto module ships scrypt() and scryptSync() functions with direct access to the N, r, and p parameters, plus a maxmem guard to cap memory use, no third-party package required.
  • Python: The standard library’s hashlib.scrypt() exposes the same n, r, p, and maxmem controls, making scrypt available in any modern Python install without extra dependencies.
  • Ruby on Rails: The has_secure_password helper has relied on bcrypt through the bcrypt gem for over a decade, storing hashes in the familiar $2a$ or $2b$ format depending on the gem version.
  • PHP: The password_hash() function defaults much of the PHP ecosystem toward bcrypt through the PASSWORD_BCRYPT constant, a setting countless WordPress plugins and custom PHP applications rely on without ever naming the algorithm explicitly.
  • Spring Security: Java’s dominant security framework ships BCryptPasswordEncoder as one of its built-in password encoders, used across a large share of enterprise Java backends.
  • Laravel: The PHP framework supports bcrypt as a configurable password-hashing driver alongside newer Argon2 options, letting teams choose per application.

The practical takeaway from that list is that neither algorithm is niche. Supporting scrypt in a language’s standard library, as Node.js and Python both do, does not mean every application built on that language actually uses it by default. Checking an application’s configuration, not assuming based on the programming language, remains the only reliable way to know which algorithm protects a given set of password hashes.

Known Limitations and Implementation Pitfalls

Neither algorithm is cryptographically broken, and most real incidents trace back to implementation mistakes rather than a flaw in the underlying math.

bcrypt’s 72-byte ceiling

Traditional bcrypt implementations only process the first 72 bytes of input. Two long passwords that happen to share the same first 72 bytes produce identical hashes, and multi-byte UTF-8 characters can hit that ceiling far sooner than a user expects, since some characters consume three or four bytes each. Applications that silently truncate without warning the user, or that fail to document the limit, create a subtle but real weakness. Older bcrypt implementations also carried version-specific quirks, including a sign-extension bug affecting high-bit password bytes in some early $2a$ implementations, which is why current libraries default to the corrected $2b$ prefix.

scrypt’s memory-exhaustion risk

scrypt’s entire security model depends on consuming a large, predictable amount of memory per check. That becomes a liability if an application accepts N, r, or p values from an untrusted source, or allows too many concurrent password checks at once. A server handling a flood of login attempts, each one claiming 128 MiB or more, can exhaust available RAM and crash under what amounts to a cheap denial-of-service attack. Node.js’s maxmem option exists specifically to cap this risk, and any production deployment should hard-code its scrypt parameters server-side rather than trusting client input, and apply rate limiting on login and password-reset endpoints regardless of which algorithm is in use.

scrypt Pros and Cons

  • Pro: Memory-hardness makes GPU and ASIC-based cracking substantially more expensive per guess than bcrypt at comparable settings.
  • Pro: Formally standardized as RFC 7914, giving implementers a documented reference rather than relying on a single research paper.
  • Pro: Available directly in Node.js and Python standard libraries with no third-party dependency required.
  • Pro: OWASP’s second-ranked recommendation when Argon2id is unavailable, ahead of bcrypt.
  • Con: Memory use (roughly 128 MiB per check at OWASP’s minimum) can strain shared hosting or high-concurrency login endpoints.
  • Con: Untrusted or misconfigured parameters create a real denial-of-service risk that bcrypt simply does not share.
  • Con: Fewer mature, battle-tested framework integrations compared to bcrypt’s decades of default-driver status.

bcrypt Pros and Cons

  • Pro: Extremely simple to configure, with a single cost factor rather than three interacting parameters.
  • Pro: Decades of production hardening across Rails, PHP, Spring Security, Laravel, and countless other frameworks.
  • Pro: Compact, predictable 184-bit output that fits cleanly into existing database schemas.
  • Pro: Minimal memory footprint, which keeps high-concurrency authentication endpoints responsive under load.
  • Con: OWASP ranks it behind both Argon2id and scrypt because it lacks memory-hardness.
  • Con: GPUs parallelize EksBlowfish efficiently, making brute-force attacks cheaper per guess than scrypt at matched cost levels.
  • Con: The 72-byte input limit is an easy detail to overlook and can quietly weaken password uniqueness guarantees.

Which Algorithm Fits Your Use Case?

The right answer depends less on which algorithm is “better” in the abstract and more on what the deployment environment can actually support.

  • New greenfield application with full control over dependencies: Use Argon2id first. If the runtime genuinely cannot support it, fall back to scrypt rather than bcrypt, since OWASP ranks it higher for good reason.
  • High-concurrency authentication service on shared or memory-constrained infrastructure: bcrypt’s small, fixed memory footprint avoids the risk of scrypt-driven memory exhaustion under heavy login traffic, making it the safer operational choice even though it ranks lower on paper.
  • Legacy Rails, Laravel, or Spring Security application already storing bcrypt hashes: Raising the existing cost factor to at least 12 is usually more realistic than a full algorithm migration, and it closes most of the practical gap with scrypt.
  • Node.js or Python backend built from scratch: Both runtimes expose scrypt natively in their standard libraries, removing the usual excuse of “no mature library available” that often pushes teams toward bcrypt by default.
  • Environment with strict FIPS-140 compliance requirements: Neither scrypt nor bcrypt satisfies that requirement on its own; PBKDF2-HMAC-SHA-256 at 600,000 or more iterations remains the OWASP-listed path for that specific constraint.
  • Cryptocurrency or proof-of-work system design: scrypt’s track record in Litecoin demonstrates real-world memory-hardness at scale, though its ASIC resistance has eroded over time as dedicated hardware caught up.

Migration Guide: Moving From bcrypt to scrypt (or the Reverse)

Password hash migrations almost always happen gradually, because neither algorithm can be reversed to recover the original password and re-hash it with the new scheme. The standard approach is to re-hash on the user’s next successful login, verified against their existing hash first.

  1. Add the new algorithm’s library alongside the existing one. Node.js and Python projects already have scrypt built in; bcrypt typically needs an established package like bcrypt or bcryptjs.
  2. Store an algorithm identifier with every password hash, not just the hash itself. A column or prefix noting “bcrypt” versus “scrypt” (and its specific parameters) avoids ambiguity during the transition period.
  3. On login, detect which algorithm produced the stored hash and verify against that algorithm specifically, rather than assuming a single scheme site-wide.
  4. If verification succeeds, immediately re-hash the plaintext password with the new target algorithm and overwrite the stored value before completing the login.
  5. Set conservative initial parameters for the new algorithm; following the OWASP minimums (N=2^17, r=8, p=1 for scrypt, cost 12+ for bcrypt) is a safe starting point, then benchmark on production hardware before raising further.
  6. Cap concurrent password-verification operations during the migration window, since a mixed-algorithm system can temporarily see both CPU-bound and memory-bound load spikes.
  7. Monitor for accounts that never log in during the migration period. Those records will keep their original hash indefinitely unless a forced password reset is triggered.
  8. Once the share of remaining legacy hashes drops low enough, consider a forced password reset for stragglers rather than maintaining dual-algorithm support indefinitely.

Teams implementing either side of this migration in Node.js can reference the site’s existing step-by-step guides for bcrypt password hashing in Node.js and Argon2 password hashing in Node.js, both of which cover the exact library calls and salt handling this migration plan assumes.

Benchmarking Both Algorithms on Your Own Hardware

The numbers in this article come from published 2026 benchmark sources, but production capacity planning should never rely on someone else’s hardware. The right move before locking in a cost factor or an N value is to benchmark both algorithms on the exact server (or server class) that will run them in production, under realistic concurrent load, not just a single-threaded loop.

For bcrypt, most languages expose a direct timing test: hash a representative password at a candidate cost factor, measure wall-clock time, and confirm it lands in an acceptable range for a login endpoint, typically somewhere between 100 and 500 milliseconds depending on the application’s latency budget. Raise the cost factor by one and re-measure; because the relationship is exponential, a single step up roughly doubles the time, so it rarely takes more than a handful of iterations to find the right setting.

For scrypt, the same timing approach applies, but memory needs tracking alongside time. Node.js’s crypto.scrypt() and Python’s hashlib.scrypt() both accept the N, r, and p parameters directly, and both support a maximum-memory guard that should be set explicitly rather than left at a default. Load-test with the number of concurrent login attempts the application realistically expects during a traffic spike, not just one request at a time, since scrypt’s memory use multiplies with concurrency in a way bcrypt’s does not. A setting that looks fine in isolation can still exhaust server memory once fifty simultaneous logins each try to claim their own 128 MiB block.

Security researchers wanting to reproduce the cracking-side numbers rather than the defender-side timing can use hashcat directly, specifying mode 3200 for bcrypt and the appropriate scrypt mode for the target format, on their own GPU hardware. That is exactly how the benchmark sources cited throughout this article generated their figures, and reproducing them locally is the most reliable way to confirm how a specific deployment’s settings hold up against current consumer hardware.

The Verdict: Which Should You Actually Use?

If Argon2id genuinely is not available, and that is a real constraint for some legacy runtimes and compliance environments, scrypt is the stronger default. Its memory-hardness pushes attackers toward expensive, specialized hardware rather than letting them scale an attack across cheap rented GPUs, and OWASP’s own preference order backs that conclusion directly. At the cost-to-crack numbers calculated earlier, a properly configured scrypt deployment at the OWASP minimum setting runs roughly $299,000 in rented GPU time to brute-force a single 8-character password, against roughly $189,000 for bcrypt at a well-configured cost factor of 12. Both numbers are high enough to make brute-forcing a single random password irrational, but scrypt keeps a meaningful lead.

bcrypt still earns its place, though, in exactly the situations where operational simplicity and memory predictability outweigh that cracking-cost gap: high-concurrency login services, resource-constrained hosting, and any codebase already built around one of the frameworks that defaults to it. Raising an existing bcrypt deployment’s cost factor to 12 or higher closes most of the practical difference without the engineering work of a full migration. The algorithm that is actually running at a safe, current configuration beats the theoretically stronger one left at a stale, low cost factor from 2015.

Frequently Asked Questions

Is scrypt more secure than bcrypt?

At comparable, properly configured settings, scrypt generally resists GPU-based cracking better than bcrypt because of its memory-hardness, which is why OWASP’s October 2026 Password Storage Cheat Sheet ranks scrypt above bcrypt when Argon2id is not available. The gap narrows considerably once bcrypt runs at a high cost factor like 12 or 13, but it does not close entirely.

Why does OWASP recommend Argon2id over both scrypt and bcrypt?

Argon2id combines memory-hardness with additional resistance to side-channel and GPU-specific attack techniques that neither scrypt nor bcrypt was designed to address, and it won the Password Hashing Competition specifically to replace both of them as the modern default. It is covered in detail in the site’s separate Argon2 vs bcrypt comparison.

Can I use scrypt and bcrypt together in the same application?

Yes, and it is common during a migration. Store which algorithm produced each password hash, verify logins against the correct algorithm, and re-hash with the new scheme once a user successfully authenticates, as outlined in the migration guide above.

What cost factor should bcrypt use in 2026?

OWASP’s floor is cost factor 10, but several 2026 security write-ups recommend 12 as a practical minimum and 13 where the server can absorb the extra latency. Whatever value is chosen should be benchmarked on the actual production hardware to confirm login response times stay acceptable.

Does scrypt really require 128 MB of memory per password check?

At OWASP’s current minimum configuration of N=2^17, r=8, p=1, the RFC 7914 memory formula works out to roughly 128 MiB of working memory per check, before accounting for implementation overhead. Lighter alternative parameter sets exist for memory-constrained environments, but they trade away some of scrypt’s cracking resistance to get there.

Is bcrypt’s 72-byte password limit actually a security problem?

It is a real limitation rather than a theoretical one. Traditional bcrypt implementations only process the first 72 bytes of input, so two long passwords sharing that prefix hash identically, and multi-byte UTF-8 characters can hit that limit faster than expected. Applications should document the limit explicitly or enforce a shorter maximum password length rather than silently truncating.

Which companies or platforms actually use scrypt today?

Litecoin’s proof-of-work consensus has run on scrypt since its 2011 launch, and both Node.js and Python expose scrypt directly in their standard libraries. Whether a given application built on those runtimes actually uses scrypt for password storage depends on its specific configuration, not just its programming language.

Should a new project just skip both and use Argon2id?

For a greenfield project with full control over its dependencies, yes, OWASP’s guidance is unambiguous about Argon2id being the first choice. scrypt and bcrypt remain relevant mainly for existing systems built around them, environments where Argon2id libraries are unavailable, or cases where bcrypt’s operational simplicity and low memory footprint are specifically valuable.