MySQL has a complex privilege scheme, allowing you to tune precisely which users and hosts are allowed to perform one or another operation. Since version 5.5, MySQL also has pluggable authentication.
Although it has advantages, this scheme is complicated. For example,
having user1@hostA
different from
user2@hostA
and user1@hostB
makes it easy to mix up their
privileges. It is even easier to do this when the username is the same and
the host changes.
MySQL allows you to tune access at the object and connection level. You can restrict a user’s access to a particular table, column, and so on.
Users usually experience two kinds of permission issues:
Users who should be able to connect to the server find they cannot, or users who should not be able to connect find that they can.
Users can connect to the server, but can’t use objects to which they are supposed to have access, or can use objects to which they are not supposed to have access.
Before you start troubleshooting these problems, you need to find out whether you can connect to the server.
After you succeed in connecting as the user you’re troubleshooting (we will discuss the case when connection is not possible a bit later in this chapter), run the query:
SELECT USER(), CURRENT_USER()
The USER()
function returns
the connection parameters used when the user connects. These are usually
the username that was specified and the hostname of a box where the client
is running. CURRENT_USER()
returns the
username and hostname pair of those privileges chosen from privilege
tables. These are the username and hostname pairs used by mysqld to check access to database objects. By
comparing the results of these functions, you can find out why mysqld uses privileges that are different from
what you expected. A typical problem is trying to use a % wildcard for the
hostname:
root>GRANT ALL ON book.* TO sveta@'%';
Query OK, 0 rows affected (0.00 sec) root>GRANT SELECT ON book.* TO sveta@'localhost';
Query OK, 0 rows affected (0.00 sec)
If I now connect as sveta
and try
to create a table, I get an error:
$mysql -usveta book
Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 30 Server version: 5.1.52 MySQL Community Server (GPL) Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>CREATE TABLE t1(f1 INT);
ERROR 1142 (42000): CREATE command denied to user 'sveta'@'localhost' for table 't1'
The problem is that the MySQL server expands sveta
to sveta@localhost
, not to the wild card:
mysql> SELECT user(), current_user();
+-----------------+-----------------+
| user() | current_user() |
+-----------------+-----------------+
| sveta@localhost | sveta@localhost |
+-----------------+-----------------+
1 row in set (0.00 sec)
If you don’t understand why one or another host was chosen, run a query like this:
mysql> SELECT user, host FROM mysql.user WHERE user='sveta' ORDER
BY host DESC;
+-------+-----------+
| user | host |
+-------+-----------+
| sveta | localhost |
| sveta | % |
+-------+-----------+
2 rows in set (0.00 sec)
MySQL sorts rows in this table from the most specific to the least
specific host value and uses the first value found. Therefore, it
connected me as the user account sveta@localhost
, which does not have CREATE
privileges.
Another issue with privileges arises when it is not possible to connect as the specified user. In this case, you can usually learn the reason from the error message, which looks similar to the following:
$mysql -usveta books
ERROR 1044 (42000): Access denied for user 'sveta'@'localhost' to database 'books'
After seeing this, you know the user credentials. Connect as the root superuser, and check whether such a user exists and has the required privileges:
mysql>SELECT user, host FROM mysql.user WHERE user='sveta' ORDER BY host DESC;
+-------+-----------+ | user | host | +-------+-----------+ | sveta | localhost | | sveta | % | +-------+-----------+ 2 rows in set (0.00 sec) mysql>SHOW GRANTS FOR 'sveta'@'localhost';
+-------------------------------------------------+ | Grants for sveta@localhost | +-------------------------------------------------+ | GRANT USAGE ON *.* TO 'sveta'@'localhost' | | GRANT SELECT ON `book`.* TO 'sveta'@'localhost' | +-------------------------------------------------+ 2 rows in set (0.00 sec) mysql>SHOW GRANTS FOR 'sveta'@'%';
+-------------------------------------------------+ | Grants for sveta@% | +-------------------------------------------------+ | GRANT USAGE ON *.* TO 'sveta'@'%' | | GRANT ALL PRIVILEGES ON `book`.* TO 'sveta'@'%' | +-------------------------------------------------+ 2 rows in set (0.00 sec)
In this output, you can see that user 'sveta'@'localhost'
has privileges only on the
database named book
, but no privileges
on the books
database. Now you can fix
the problem: give user sveta@localhost
the necessary privileges.
The previous examples discussed users who lacked necessary privileges. Users who are granted superfluous privileges can be handled in the same way; you just need to revoke the unnecessary privileges.
Warning
MySQL privileges are detached from objects they control: this means mysqld does not check for the existence of an object when you grant a privilege on it and does not remove a privilege when all objects it grants access to are removed. This is both a great advantage, because it allows us to grant necessary privileges in advance, and a potential cause of an issue if used without care.
As a best practice, I recommend careful study of how MySQL privileges work. This is especially important if you grant privileges on the object level because you should understand how a grant on one level affects grants of others. The same considerations apply to revoking privileges, which can be even more critical because if you think you revoked a privilege and it is still present, this allows unwanted access.
Get MySQL Troubleshooting now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.