The MD5 hash of a string will always be the same. That is one of the largest weaknesses of MD5. So we know that if we hash a users password and store it in the database that we can compare the hashed password in the database to the password they supplied and we hashed for comparison. So let's say Mr. Cracker gets a hold of the userass list for everyone in the database. Well he can in theory crack the hashes of the passwords using rainbow tables. Now I won't go too into detail about rainbow tables, but just think of it as a huge table of words and their MD5 hashes together. What they do is scan through the tables looking for a match. Similar to the way we compare the hashes for logging a user in, only they have the plain text version too. Now if we decided we wanted to hash the password "lolwut" using the MD5 algorithm we would go: md5("lolwut"); PHP: Now the MD5 hash of "lolwut" is "05a208028929fd77cfb5b08096a837df" and it always will be. Now all a "salt" is, is just a string appended to the password before it gets hashed. So say we use the salt "25tks8j3s5" for every password for every user that registers. We achieve that by doing something similar to this: md5("lolwut"."25tks8j3s5"); PHP: That will result in the new hash for our user becoming "229ade86bcc789ed3239bc533f16f7b3". This is obviously different from our regular non-salted hash of "05a208028929fd77cfb5b08096a837df". This alone is fairly good because it breaks the standard rainbow table. Mr. Cracker would have to make a custom rainbow table with our salt at the beginning for each word in his table to try to crack the userass list. If we decided to stop here (which some do) that would be, ok. But why? Let's make it even harder for Mr. Cracker. If we could have a a random salt for each individual user then it would be near impossible to crack all the passwords. Why? Mr. Cracker over here would have to spend the time to make a new rainbow table for every password he wanted to crack because each of the salts would be different. (I'm assuming here that anyone who has your userass list is also clever enough to retrieve all the salts for each user. This is also assuming that your storing the salts for each user inside the database next to their password or wherever it gets placed). Here is a function I wrote (with some generous help from Google) to generate a random salt. //generates a random salt for use when crypting user passwords //includes all upper and lower case, numbers, and common symbols (no ALT code symbols) function gen_salt($length) { $salt = ""; $possible = "abcdefghjklmnpqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_-+=[]{}\/.,?<>`~"; $i = 0; while($i < $length) { $char = substr($possible, mt_rand(0, strlen($possible) - 1), 1); $salt .= $char; $i++; } return $salt; } PHP: Using the function above we can generate a fairly random salt for a user. Like so: $salt = gen_salt(15); $pass = "lolwut"; md5($pass.$salt); PHP: Then of course you would store the salt that was generated and the hash of the salted password inside the database for the user. Now that the salt and the hash of the salted password are in the database, say a user wanted to login. We grab his username, query the database for it, find the row with his username which will contain his salt and password hash. Then we can append the salt to the password the user provided when trying to login, hash it, then compare that to the hash of the salted password inside the database. The length of the salt doesn't necessarily have to be uber long either. I would however recommend something about 15 chars long. Now with the salt being appended at the beginning of the password. You could take it even another step further by appending something already being stored in your database that Mr. Cracker would be thinking of. For example, the IP address the user registered with, or the register date, their username. Remember, "security through obscurity" often works quite well.