One of the biggest problems when engineering a password storage scheme using salting and hashing, as should be the minimum, is to separate user-specific salts from user-specific password hashes, in order to reduce the direct applicability of a rainbow table (don’t ever assume that your “algorithm” is safe from the hashes and salts themselves.) There are a lot of more or less silly suggestions out there as to how to do this, but recently Jeremy Spilman wrote a two part series on what seems like a reasonably good approach.
While his initial idea was inherently flawed, he corrected a lot of this in the follow-up post. The “algorithm” relies on the complexity of modern hash algorithms while storing salted hashes relationally disjoint from users but with verifiable joint traits and the ability to increase the entropy of the joint relationship through noisy data. If you’re still storing hashes with a relational link, try thinking about how low the complexity of getting one specific user’s password is.