There are still loads sites that are making mistakes with user passwords including:
  1. Artificially limiting the length
  2. Having too strict a policy on letters, numbers, special chars etc.
  3. Having no minimum length (honestly!)
  4. Not storing passwords correctly
  5. Not blacklisting common patterns or words
Doing it correctly is not massively hard so here we go: best practice for passwords.

Strength

Firstly, password strength comes with both length and complexity. A common good practice is for people to use long phrases instead of complex passwords and a phrase of 50 characters is NOT vulnerable to cracking, as long as it is not a well-known or published phrase. Do not force users to have other types of character sets if you can detect that their passphrase is long enough.

On the other hand, if you can count the types of character and can detect that it is random, a length of 10 is more than enough (if it is randomnly generated, it is likely to be longer anyway)

User education

Trying to force users down a certain behaviour is fraught with dangers, not least of which is that they might not bother with your site!

The best way to educate users is to have a number of hints. Firstly, a password strength meter that uses combination of pattern matching, length and number of characters to determine an approximate strength. Do not use this rigidly though because there are often strong passwords that are not measured as such and vice-versa.

Also, tell the user that the best passwords are randomnly generated and stored in a password utility like Keepass, although they are only useful if you usually log in from a tablet or desktop. If they need to remember it, tell them to use a long random-ish phrase like lukelikespancakesfrommikesshop although if you are mobile, this is also going to be a pain.

Length

You should always have a minimum length, currently 8 is considered reasonable. The only reasonable max length of a password is > 128 characters. Most people will never need to use this much but since you are hashing passwords anyway, the length doesn't matter except for physical reasons like HTTP size and potential DoS with larger passwords.

What you mustn't do (I have seen it) is allow any length but truncate what is entered to a certain length like 12 characters before storing it. This implies you are stronger than you are and can cause problems like weaker password cracking and inconsistent sizes of text boxes which make some pages work differently from others.

Storage format

There is NEVER a reason to store passwords in plain text. In most cases, there is no reason to use symmetrical encryption. Why? Because no one should be able to find your password, not the admin of the site or anyone else. If it is forgotten, you have a reset process for that reason!

There are a number of choices for storage format. bcrypt, scrypt. pbkdf2 and argon2 are all reasonable candiates...but...choose a raw format like the password hashing contest format that allows you to change or upgrade the cost at a later date without doing anything to the code.

This involves using password methods in the same way that PHP does it. Verify the password and then if successful, find out if it needs a rehash, while you have the correct password available.

Blacklisting

This is another area that is difficult. You could blacklist every password that has ever been leaked online, since a hacker would have these available to try as a first sweet attack against passwords...but... if you do, it is likely you will lose customers, especially after their first 3 attempts are blocked by your system. A better idea is a combination of the strength meter, instructions that could be dynamic like, "It appears you have typed AaaaaaNNNNC" which is a very common pattern and makes your password easier to brute-force, please consider changing it or using a password manager.

Two-factor

Two-factor auth is a great way to protect your front-end login pages but note that it does not protect your data if the database was stolen and an attacker was brute-forcing everything. Consider your main threats and decide whether this is worth the additional work.

Two factor with TOTP is free and easy using something like Google authenticator, which simply derives a numeric code every 30 seconds from a shared secret. This and others are a great protection from phished credentials BUT you need to consider what happens when the user loses their phone or otherwise can't get the code. The TOTP reset has the potential to bypass all of the protection it provides so how are you going to do that? Banks and the like carry enough info to identify you in this scenario but if you do this wrong, you will get accounts hijacked.

Password Reset

Most password resets simply send an email with a link. Without going into too many details, this should contain a nonce to prevent replaying the reset process and should probably only be valid for 20 to 60 minutes. You need to carefully ask whether this in itself is enough protection. Although they might only have needed to access the email account to create the account in the first place, accounts often gain value over time and simply accessing the email account in the future might not be enough assurance that this is the real user.

You have a number of options here. You could use the 2-factor approach which gives a reasonable second point of assurance and although you can use security questions, you have to be careful to only ask questions that will have an easy to remember and unchanging answer and ideally not something that can be gleaned from Social media.

Bad questions:
  1. Where were you born?
  2. Who is your oldest sibling?
  3. What is your favourite food?
Better Questions:
  1. What was the name of your first pet?
  2. Where did you have your first accident? 
  3. What was the registration of your first car?
Security questions have a mixed reception in the passwords world because they are so easy to misuse. I remember one guy who thought he was being clever by picking any question at random and always answering the same thing like Volkswagen1973 since an attacker would never guess that as an answer but what happens if he can't remember the answer or someone hacks a site where answers are stored in plain text and now knows the trick?

If you use security questions, trim them, lower-case them and hash them like a password. Make sure the user knows that they are case-insensitive, it will just make things easier all round.