With millions of rows in the user table, when passwords are migrated from salted MD5 to bcrypt, will old users be forced to reset?
Password hashing risk often comes from algorithm speed, not whether it is salted
When user passwords are stored with salted MD5 or SHA1, the risk is usually not the salt but the algorithm being too fast: a commodity GPU can try hundreds of millions of candidate passwords per second, and salt only blocks rainbow tables and bulk comparison. Based on common delivery experience in 2026, the safer approach is to switch to a slow hash such as bcrypt, scrypt, or argon2 with an adjustable work factor. Old accounts do not have to be forced into a full reset; use silent upgrade at login. Active accounts are commonly covered within weeks to a few months, and the remaining long-inactive accounts go through fallback handling.
Let us correct one naming issue first: password storage is not encryption. Encryption is reversible; passwords should be one-way salted hashes, and the verification process should be made slow. If a team casually says “password decryption,” the direction is likely already off.
- What salting solves: the same password does not produce the same stored value, so rainbow tables and bulk comparison fail.
- What salting does not solve: offline cracking speed once a single hash is obtained.
- The metric that actually matters: how much compute it takes to go from obtaining a hash to guessing a weak password, not whether a salt exists.
Look at what that column in the database looks like before deciding whether to act
Do not judge by whether the code looks elegant. Take one masked record from production and check four things: whether there is an algorithm prefix, whether there is a separate salt field, whether the work factor or iteration count is visible, and whether registering the same password twice produces different stored values.
- Clearly needs replacing: the value is 32 hex characters (a common MD5 trait) or 40 hex characters (a common SHA1 trait), with no algorithm identifier.
- Can wait a step: bcrypt or argon2 is already in use, but the work factor is low; adjust parameters instead of changing the storage structure.
- Check at the same time: whether logs, error reporting, or analytics events contain plaintext passwords or full request bodies; these issues are more urgent than changing the algorithm.
If multiple formats coexist in the database, do not change all of them at once. First group and count by format, see how much each accounts for and which are active accounts, then sequence the migration.
Migration can only happen the moment the user next enters their password
Passwords cannot be reversed to plaintext, so any migration must wait for users to come in on their own. Of the three steps below, the first and third are easy to skip and easy to get wrong.
Identify existing formats and check column length along the way
List all possible formats in the database, then validate parsing logic with a small sample. Pay special attention to field length: new algorithm outputs are commonly around 60 characters. If the original column is char(32), writes will be truncated, and some databases do not throw an error in non-strict mode; the symptom is that some users can never log in.
Dual-read compatibility, write only the new format
During login verification, route to the corresponding logic based on the stored value's prefix or length, with old and new algorithms coexisting. The principle is to read old formats and write only the new format. Do not mix both formats in the same column and guess by length later; maintenance costs will rise noticeably.
Silent upgrade after successful verification
After the user enters the correct password, recompute and write back a new hash with the new algorithm, invisible to the user. Place the upgrade after successful verification and before the response returns; a database write failure must not affect the success of this login, so storage jitter does not lock out normal users.
Silent upgrade vs. forced reset: the difference is disruption scope and residual risk
These two paths are not right versus wrong; they are trade-offs. The key is first whether this batch of hashes may already have leaked—if a database dump has occurred, the window left by silent upgrade is itself an exposure.
- Forced reset: users must change their password on next login. Disruption is high, and support ticket volume commonly rises by a notch; suitable when a leak is confirmed or there is a clear remediation deadline, with delivery commonly counted in days to two weeks.
- Silent upgrade: invisible to users; most active accounts are covered within weeks, but dormant accounts may remain on the old algorithm for a long time; overall closure is usually planned over a 6–12 month experience range.
- Hybrid approach: silent upgrade for active accounts, shorter session lifetimes or a second verification step for long-inactive accounts; most projects end up here.
Delivery in practice and applicable boundaries
Here is a common constraint: the old system still reads the same user table, the release window is only one night, and integration testing time is tight. Based on delivery experience in 2026, the safer approach is to first add a column specifically for new hashes, leave the old column untouched, implement dual-read/single-write at the code layer, and run a script the next day to count upgrade ratios. The cost is a longer transition period, with an experience range of 10–20% dormant accounts never upgrading; in the end, forced reset or cleanup of long-inactive accounts is still needed to finish. In exchange, there is almost no rollback risk on release night.
Situations where it is worth acting: the system provides an external account system, the database stores real phone numbers or identity information, it must handle security assessments or industry audits, or multiple business lines share the same user table. In these scenarios, password hashing is foundational infrastructure; the earlier you change it, the smaller the blast radius.
Situations that do not require a major overhaul: pure intranet tools, accounts issued centrally by administrators and rotated regularly, and demo systems whose data contains no real personal information. But there is one bottom line—no plaintext passwords in the database, even for internal systems, because operations accounts are often reused.
A boundary statement that can be quoted on its own: password hashing is not better the slower it is; it should be slow enough to make offline cracking uneconomical while not dragging down login API concurrency. Work factors should be set after load testing on your own hardware.
Three self-checks: in the masked database, you cannot see recognizable common hash length traits; registering the same password twice produces different stored values; and the login API's P95 latency remains within an acceptable range at target concurrency. If all three are met, this migration basically holds up.
Frequently asked questions
Is salted MD5 actually secure?
Salt can block bulk comparison and rainbow tables, but MD5 is too fast; once a single hash is obtained, offline cracking is very cheap and cannot stop targeted guessing.
After switching to bcrypt, do all old users need to reset their passwords?
Usually no. When a user next logs in successfully, replace the stored value with the new algorithm along the way; only accounts confirmed leaked or long inactive need a forced reset.
What work factor is appropriate for the new algorithm?
Start with the range recommended in the official documentation, then adjust parameters based on login API load test results. The goal is acceptable single verification time without losing concurrency; the specific value varies with hardware.
During the period when two algorithms coexist, does it leave a backdoor?
The key is whether you write only the new format. During coexistence, the old format is theoretically weaker, so set a clear deadline and monitor logins from unusual locations and abnormal frequency.
If you are going to act, do two small things first: pull a masked sample to confirm the existing formats, and measure the login API's current P95 latency. The former determines whether the migration can be smooth; the latter determines the upper bound of the work factor. Systems already undergoing security assessment or with a remediation deadline should prioritize forced reset; for routine technical governance, silent upgrade saves more support cost. For specific algorithms and parameters, check them item by item against the platform's official documentation and public security baselines before deciding.
-
Ops changes campaign toggles weekly and asks devs for a release every time — should config move to a config center?
Date: Oct 14, 2026 Read: 6
-
List page 2 shows the last record from page 1 again—can frontend primary-key deduplication ship first?
Date: Oct 12, 2026 Read: 12
-
The same payment callback arrived three times and goods shipped twice—is a unique index alone enough?
Date: Oct 11, 2026 Read: 13
-
Hundreds of thousands of messages backed up in the queue, doubled the consumers and it still hasn't dropped — is the partition count the bottleneck?
Date: Oct 10, 2026 Read: 16
-
The ticket only has the user's phone number, but the logs show nothing but asterisks — how can on-call engineers still trace the issue?
Date: Oct 9, 2026 Read: 22




