Search the MySQL manual:

4.2.9 Access Control, Stage 1: Connection Verification

When you attempt to connect to a MySQL server, the server accepts or rejects the connection based on your identity and whether you can verify your identity by supplying the correct password. If not, the server denies access to you completely. Otherwise, the server accepts the connection, then enters Stage 2 and waits for requests.

Your identity is based on two pieces of information:

Identity checking is performed using the three user table scope fields (Host, User, and Password). The server accepts the connection only if a user table entry matches your hostname and user name, and you supply the correct password.

Values in the user table scope fields may be specified as follows:

Non-blank Password values represent encrypted passwords. MySQL does not store passwords in plaintext form for anyone to see. Rather, the password supplied by a user who is attempting to connect is encrypted (using the PASSWORD() function). The encrypted password is then used when the client/server is checking if the password is correct. (This is done without the encrypted password ever traveling over the connection.) Note that from MySQL's point of view the encrypted password is the REAL password, so you should not give anyone access to it! In particular, don't give normal users read access to the tables in the mysql database! From version 4.1, MySQL employs a different password and login mechanism that is secure even if TCP/IP packets are sniffed and/or the mysql database is captured.

The examples here show how various combinations of Host and User values in user table entries apply to incoming connections:

Host value User value Connections matched by entry
'thomas.loc.gov' 'fred' fred, connecting from thomas.loc.gov
'thomas.loc.gov' '' Any user, connecting from thomas.loc.gov
'%' 'fred' fred, connecting from any host
'%' '' Any user, connecting from any host
'%.loc.gov' 'fred' fred, connecting from any host in the loc.gov domain
'x.y.%' 'fred' fred, connecting from x.y.net, x.y.com,x.y.edu, etc. (this is probably not useful)
'144.155.166.177' 'fred' fred, connecting from the host with IP address 144.155.166.177
'144.155.166.%' 'fred' fred, connecting from any host in the 144.155.166 class C subnet
'144.155.166.0/255.255.255.0' 'fred' Same as previous example

Because you can use IP wildcard values in the Host field (for example, '144.155.166.%' to match every host on a subnet), there is the possibility that someone might try to exploit this capability by naming a host 144.155.166.somewhere.com. To foil such attempts, MySQL disallows matching on hostnames that start with digits and a dot. Thus, if you have a host named something like 1.2.foo.com, its name will never match the Host column of the grant tables. Only an IP number can match an IP wildcard value.

An incoming connection may be matched by more than one entry in the user table. For example, a connection from thomas.loc.gov by fred would be matched by several of the entries just shown above. How does the server choose which entry to use if more than one matches? The server resolves this question by sorting the user table after reading it at startup time, then looking through the entries in sorted order when a user attempts to connect. The first matching entry is the one that is used.

user table sorting works as follows. Suppose the user table looks like this:

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| %         | root     | ...
| %         | jeffrey  | ...
| localhost | root     | ...
| localhost |          | ...
+-----------+----------+-

When the server reads in the table, it orders the entries with the most-specific Host values first ('%' in the Host column means ``any host'' and is least specific). Entries with the same Host value are ordered with the most-specific User values first (a blank User value means ``any user'' and is least specific). The resulting sorted user table looks like this:

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| localhost | root     | ...
| localhost |          | ...
| %         | jeffrey  | ...
| %         | root     | ...
+-----------+----------+-

When a connection is attempted, the server looks through the sorted entries and uses the first match found. For a connection from localhost by jeffrey, the entries with 'localhost' in the Host column match first. Of those, the entry with the blank user name matches both the connecting hostname and user name. (The '%'/'jeffrey' entry would have matched, too, but it is not the first match in the table.)

Here is another example. Suppose the user table looks like this:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| %              | jeffrey  | ...
| thomas.loc.gov |          | ...
+----------------+----------+-

The sorted table looks like this:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| thomas.loc.gov |          | ...
| %              | jeffrey  | ...
+----------------+----------+-

A connection from thomas.loc.gov by jeffrey is matched by the first entry, whereas a connection from whitehouse.gov by jeffrey is matched by the second.

A common misconception is to think that for a given user name, all entries that explicitly name that user will be used first when the server attempts to find a match for the connection. This is simply not true. The previous example illustrates this, where a connection from thomas.loc.gov by jeffrey is first matched not by the entry containing 'jeffrey' as the User field value, but by the entry with no user name!

If you have problems connecting to the server, print out the user table and sort it by hand to see where the first match is being made. If connection was successful, but your privileges are not what you expected you may use CURRENT_USER() function (new in version 4.0.6) to see what user/host combination your connection actually matched. See section 6.3.6.2 Miscellaneous Functions.

User Comments

Posted by David Beecher on Thursday September 12 2002, @2:38pm[Delete] [Edit]

I installed the binary distribution on a new
server running solaris 2.7 (although this could
happen on anything). When I went to set the
initial password for root and root@myhost per the
INSTALL documentation it accepted the root
password but then said it would not allow
connections from the fully qualified domain name
(myhost.myhome.com) of the server it resided on...
Of course I looked at the Host and User columns in
the mysql:user table and didn't get anywhere....
finally I realized it was using the FQDN from the
/etc/hosts file (which when properly formatted
includes IP,FQDN,NAME,ALIAS,ALIAS,ALIAS). Updated
/etc/nsswitch.conf to use dns and voila, it works
fine now). Easy to overlook.

Posted by LeRoy Michaelson on Wednesday December 18 2002, @5:27pm[Delete] [Edit]

After viewing the previous comment, I solved a
similar problem. Apparently mySQL doesn't like hard
addressses. I coun't login to mySQL from a remote
client no matter what permissions I gave the user.
Once I added an entry like the following:

<blockquote>
192.214.33.156 myRemoteHost
</blockquote>
to the /etc/hosts file, problem was solved.

Posted by [name withheld] on Friday January 31 2003, @8:31pm[Delete] [Edit]

Under 3.23.55 with syntax as follows:
GRANT ... ON `foo\_bar`.* TO ...

results in:
Unknown command '\_'

However it appears the grant tables are still updated.
Strange

Posted by a f on Tuesday March 11 2003, @3:18pm[Delete] [Edit]

I have Redhat 8 and had a problem connecting using telnet test (refused). Seems it was trying to connect as localhost.localdomain. Swapped the order in /etc/hosts for 127.0.0.1 and it then connected ok. OpenCms now installing ok...

Posted by maelstrom on Tuesday March 25 2003, @12:22pm[Delete] [Edit]

Something this doesn't mention is that you can only use the % between dots.
Example:
%.com works.
www.%.com works.
www%.com does not work.

Posted by [name withheld] on Tuesday June 24 2003, @5:43am[Delete] [Edit]

A common problem is getting an "xxx is not allowed to connect to this MySQL server" message when connecting to a remote MySQL server despite having edited the user table in mysql db.
What solved the problem for me (after 2 hours) was just executing "FLUSH PRIVILEGES;".

Posted by [name withheld] on Friday July 25 2003, @7:42pm[Delete] [Edit]

I had a very similar problem after migrating my databases to a new MySQL installation on a different machine. All efforts to connect to the server from a networked PC failed until I realized that PHPMyAdmin didn't automatically enter new user passwords using the password() function. Once I re-entered the password through the function, I connected easily with the new user's credentials.

Interestingly enough, I still cannot connect via any other username/password combination - just the new user I created.

Add your own comment.