Hashing on client side is both more private, and secure. All the user ever submits is a combined hash (auth/pubkey) of their username + password.
If the server has that hash? Check the DB if it requires 2FA, and if the user sent a challenge response. If not, fail the login.
Registering is pretty much the same. User submits hash, server checks DB against it, fail if exists.
Edit: If data is also encrypted properly in the DB, it doesn't even matter if the entire DB is completely public, leaked, or secured on their own servers.