The first problem I suspect you will encounter (and it's big) is that your database does not have a password hash function. Of course, it probably has MD5 () and SHA1 (), but these are cryptographic hash functions. Does it have bcrypt () or scrypt () or PBKDF2 ()?
Using a cryptographic hash function rather than a password hash function means that LinkedIn passwords can be cracked so quickly. If you do not use one of the above functions, you will be vulnerable if your hashes leak.
Going further to answer your question, assuming your database supports a password hash algorithm (using bcrypt simply because I have to choose one). These two alternatives are:
Database hashing:
$db->query("SELECT COUNT(*) FROM users WHERE username = '?' AND password = BCRYPT(?, (SELECT salt FROM user WHERE username = '?'))", $username, $password, $username); if($row['count'] != 1) {
In this case, the raw password is sent to the database and a simple yes or no (1 or 0) is returned. This database connection can be encrypted. Hash and salt are never contained in the application.
Application hashing:
$db->query("SELECT username, salt, password FROM users WHERE username = '?', $username); if(bcrypt($password, $row['salt']) != $row['password']) { // Not authenticated. Throw exception. }
In this case, the hash and salt are pulled from the database into the application, and the hash of the raw password and comparison is performed there. Communication with the database can still be encrypted. A raw password is never stored in database memory.
For efficiency, we can assume that both hashing algorithms are written in C (or in some compiled language) and may be provided by the OS, so take the same time. The hash option of the application receives more data over the wire, and the hash option of the database sends more and has a more complex request (essentially two requests, one for salt and the other for comparison). It may not be possible to use the index as I wrote this query, but the query can be rewritten. Since the data size in both cases is likely to remain a single TCP packet, the speed difference will be negligible. I would call it a win for hashing an application due to a subquery.
For exposure. I would find the raw password more sensitive than hash and salt. Therefore, limiting the impact of a raw password seems like a safer bet, which makes hashing a best practice.