I have a user 'myuser' and two databases. 'db1' and 'db2'.
'myuser' already has rights to use db1 and I wanted to grant him additional permission to use 'db2' by using the following query:
GRANT ALL ON db2.* TO 'myuser'#'localhost';
After I ran the grant statement, 'myuser' lost the connection to the first database 'db1'
I'm afraid that I used a wrong host name. Instead of 'localhost' I should have used '%'.
When I do:
select host from mysql.user where user = 'myuser';
Now I see two host records '%' and 'localhost' for that user
When I run SHOW GRANT statements I get permissions for different hosts. 'localhost' and '%'.
mysql> SHOW GRANTS FOR 'myuser'#'localhost';
+----------------------------------------------------------------------+
| Grants for myuser#localhost |
+----------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'myuser'#'localhost' |
| GRANT ALL PRIVILEGES ON `beta_version`.* TO 'myuser'#'localhost' |
+----------------------------------------------------------------------+
and
mysql> SHOW GRANTS FOR 'myuser'#'%';
+-----------------------------------------------------------------------------------------------------------+
| Grants for myuser#% |
+-----------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'myuser'#'%' IDENTIFIED BY PASSWORD '*6ASDFASDFASDF...'
| GRANT ALL PRIVILEGES ON `myuser`.* TO 'myuser'#'%'
+-----------------------------------------------------------------------------------------------------------+
What happened that caused 'myuser' to not work in my PHP scripts and in phpMyAdmin?
MySQL identifies a user by BOTH the username and the host. When MySQL does the authentication at login, MySQL first looks for a hostname that is an exact match. If it doesn't find an exact match, then it looks for a host containing a '%' wildcard.
When you did the GRANT ... TO myuser#localhost, MySQL created a new user (with no password, because there was no IDENTIFIED BY given in the statement.
Then what happened, when you attempted to login as myuser from the localhost, mysqld tried to find an entry that matched 'myuser'#'localhost' in the mysql.user table and it found it. And the session got the privileges assigned to that user.
(To be a little more precise, mysqld doesn't really look at the contents of the mysql.user table, what it really looks at the in-memory structure, which was populated from the table when it was built. A rebuild of the memory structure is triggered by a GRANT, a REVOKE or a FLUSH PRIVILEGES statement.)
What was happening BEFORE you added that new user, mysqld was looking for an exact match on user and hostname, and didn't find one. But it did find an entry with the '%' wildcard, so it matched to that, so the session got all the privileges granted to the 'myuser'#'%' user.
The two users 'u'#'%' and 'u'#'localhost' are separate and distinct from each other. Privileges must be granted to each user individually. Any privileges granted to 'u'#'%' apply ONLY to that user and NOT to 'u'#'localhost'.
USAGE means "no privileges and that is what you have given your user when connecting from localhost.
I think localhost takes precedence over % so when the user is connecting from localhost that is the grant that will be used.
Grant access to both schemas to % (or localhost if that is what you prefer) and it should be clear and work better.
Related
Oddly enough it seems my mysql will not allow creating a user with access to a specific database. Using MySQL Workbench:
CREATE USER 'testUser'#'localhost' IDENTIFIED BY 'thepasswordhere';
GRANT ALL PRIVILEGES ON testDatabaseName TO 'testUser'#'localhost' WITH GRANT OPTION;
SHOW GRANTS;
I see nothing mentioning granted privileges for the created user. This explains why I get mysqli::mysqli(): (28000/1045): Access denied for user 'testUser'
What step am I missing?? Update: Even when I mistype the username I still get a success with 0 rows affected: GRANT ALL PRIVILEGES ON testDatabaseName TO 'testkUser'#'%' WITH GRANT OPTION; so I think something's seriously wrong with my local mysql. Any ideas on a fix?
CREATE USER 'testUser'#'localhost' IDENTIFIED BY 'thepasswordhere';
GRANT ALL PRIVILEGES ON testDatabaseName.* TO 'testUser'#'localhost' WITH GRANT OPTION;
SELECT sql_grants FROM common_schema.sql_show_grants;
What changed? I simply added a .* after database name. It's necessary so the user has access to all tables inside the database.
Also for the latest mysql, I believe you need to put user password when using grant.
So do as follows:
CREATE USER 'testUser'#'localhost' IDENTIFIED BY 'thepasswordhere';
GRANT ALL PRIVILEGES ON testDatabaseName.* TO testUser#localhost IDENTIFIED BY 'pass' WITH GRANT OPTION;
FLUSH PRIVILEGES;
SELECT sql_grants FROM common_schema.sql_show_grants;
As mentioned by Michael in the question comments:
SHOW GRANTS FOR 'testUser'#'localhost';... otherwise, SHOW GRANTS;
shows your privileges -- the ones associated with the account that is
currently logged in.
I have foo_bar_test database existing on my mysql server on host 127.0.0.1.
But there's no user that can access it but root, and I don't want to use root user anywhere in my code. So I created new user, fb_test, and granted him privileges for this database:
create user fb_test#'127.0.0.1' identified by password 'some_password';
grant all on 'foo_bar_test.*' to fb_test#'127.0.0.1';
flush privileges;
Ok, that should work, but when I log in as this user, I don't have any database available!
What's wrong?
I checked it using show grants for fb_test#'127.0.0.1', but it shows some strange results:
grant usage on *.* to fb_test#'127.0.0.1' identified by password '*another_password_dont_know_which_one'
How do I solve this?
you have an error in grant statement. Use the query:
grant all on 'foo_bar_test'.* to fb_test#'127.0.0.1';
In fact your grant command results an error which I think you ignored.
Here is what I do to check grants for a specific user:
mysql> SHOW GRANTS FOR mmuser1;
+-----------------------------------------------------------------------------------------------------------------+
| Grants for mmuser1#% |
+-----------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'mmuser1'#'%' IDENTIFIED BY PASSWORD '*fesfesfesfes' |
| GRANT ALL PRIVILEGES ON `shopping_mm`.* TO 'mmuser1'#'%'
However, if I do the following:
mysql -ummuser1 -p
I can acccess and query another database (sports). Also, when doing:
SELECT Db,User FROM db;
I can see this Db associated with this user.
How is it possible that is not showing in the Grants table?
As documented under SHOW GRANTS Syntax:
If you specify only the user name part of the account name, a host name part of '%' is used.
It is likely that you have granted permission to your user with an explicit hostname, e.g. 'mmuser1'#'localhost'. As documented later on the same page, this can be verified once connected:
To list the privileges granted to the account that you are using to connect to the server, you can use any of the following statements:
SHOW GRANTS;
SHOW GRANTS FOR CURRENT_USER;
SHOW GRANTS FOR CURRENT_USER();
Or, alternatively, simply inspect CURRENT_USER:
SELECT CURRENT_USER;
Maybe you have a wildcard user that is usually default in Mysql is setup?
Any or % for the user name or host will allow any username/host permission to the DB, like in the picture below
You should remove these users that are usually default in MySQL
This picture is the default accounts that are installed with MYSQL , and all of them should be deleted as soon as you create a new user as none of them are secure, they allow - any username USAGE access to the db's
In my PHP script, I'm accessing two databases db1 and db2. I have a user myuser#localhost that can access db1 but can't access db2.
When selecting from mysql.user table, there is one record and the host for that user is a wildcard %, there isn't a localhost host.
SELECT user, host FROM mysql.user WHERE user = 'myuser'; give me:
+------------+------+
| user | host |
+------------+------+
| myuser | % |
+------------+------+
1 row in set (0.00 sec)
Looking at GRANTS for that user, I see same permissions for db1 as for db2
SHOW GRANTS FOR 'myuser'#'%';
+-----------------------------------------------------------------------------------------------------------+
| Grants for myuser#% |
+-----------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'myuser'#'%' IDENTIFIED BY PASSWORD '*7733323232...' |
| GRANT ALL PRIVILEGES ON `db1`.* TO 'myuser'#'%' |
| GRANT ALL PRIVILEGES ON `db2`.* TO 'myuser'#'%' |
+-----------------------------------------------------------------------------------------------------------+
In my PHP script I can access db1 however I get an error: INSERT command denied to user 'myuser'#'localhost' for table 'HISTORY'.
It says user is myuser#localhost and people suggested adding permission for myuser#localhost however, why does this user have access to db1 and not to db2?
localhost does not match % in MySQL. It seems like it should, but in fact it doesn't. You'd have to separately grant privileges to user#localhost, both for the USAGE privilege, and for the privileges on each database.
Or you can connect as user#127.0.0.1 which does match %. Using the IP address for localhost seems like it should work identically to localhost, but it doesn't. You need to have two lines in the mysql.user table (and also in the mysql.db table in your case) to enable both.
To demonstrate the difference between localhost and 127.0.0.1:
Connecting as mysql -h localhost uses the UNIX socket interface, and bypasses TCP/IP. This can be slightly better for performance, but it has the effect on grant matching described above.
You can force a local TCP/IP connection by connecting as mysql -h 127.0.0.1. Then it will pick up the grants you have made to myuser#%.
So to get the same user, password, and privileges for both the socket interface and the TCP/IP interface, you'd need to run all of the following statements:
GRANT USAGE ON *.* TO 'myuser'#'%' IDENTIFIED BY PASSWORD '*7733323232...'
GRANT USAGE ON *.* TO 'myuser'#'localhost' IDENTIFIED BY PASSWORD '*7733323232...'
GRANT ALL PRIVILEGES ON `db1`.* TO 'myuser'#'%'
GRANT ALL PRIVILEGES ON `db1`.* TO 'myuser'#'localhost'
GRANT ALL PRIVILEGES ON `db2`.* TO 'myuser'#'%'
GRANT ALL PRIVILEGES ON `db2`.* TO 'myuser'#'localhost'
If you haven't done that already, you need to run flush privileges so that mysql knows there was a change and reloads the privileges table for users:
FLUSH PRIVILEGES;
This very likely has nothing to do with GRANTs.
A very common reason for having incorrect access rights is because of default users that exist in MySQL. Specially ones with '' for User (anonymous users) and/or Host in mysql.user table. Because of the way MySQL handles authentication and proxy users, and the sorting rules used on mysql.user table entries, one could end up using an unexpected user than the one they used for authentication.
Use SELECT USER(); to find out the connecting user that was used during authentication and SELECT CURRENT_USER(); to find out the effective user whose privileges apply during the current session.
And from http://dev.mysql.com/doc/refman/5.6/en/connection-access.html
It is a common misconception to think that, for a given user name, all
rows that explicitly name that user are used first when the server
attempts to find a match for the connection. This is not true.
If you are able to connect to the server, but your privileges are not
what you expect, you probably are being authenticated as some other
account.
A mysql.user table similar to following
+-----------+----------+-
| Host | User | ...
+-----------+----------+-
| % | root | ... (root from any host)
| % | jeffrey | ... (jeffrey from any host)
| localhost | root | ... (root from localhost)
| localhost | | ... (any user from localhost)
+-----------+----------+-
becomes,
+-----------+----------+-
| Host | User | ...
+-----------+----------+-
| localhost | root | ...
| localhost | | ...
| % | jeffrey | ...
| % | root | ...
+-----------+----------+-
whenever the server reads the user table into memory, in order to handle multiple matches.
When a client attempts to connect, the server looks through the rows in sorted order and uses the first row that matches the client host name and user name.
Precedence is given as: values (IP address, host name, user name, etc.) > '%' > ''
Most of the time application server/client is running in the same host as the database, causing the host name to be picked up as localhost during authentication.
mysql -u jeffrey uses jeffrey#localhost which gets matched against ''#localhost instead of jeffrey#%.
Executing $MYSQL_HOME/bin/mysql_secure_installation will remove anonymous users, while securing the installation, alleviating this unexpected behaviour.
Also check:
[1] http://bugs.mysql.com/bug.php?id=36576 (check comment before last)
[2] http://bugs.mysql.com/bug.php?id=69570
Just thought I'd add an answer. I was trying this on ubuntu. Tried the grants, flushes, nothing worked (this is immediately after by apt-get install mysql-server). Just for grins I bounced the server, that worked and my new user can now login. I did:
sudo service mysql restart
I don't know what that worked, but it did.
You must GRANT privileges also to 'myuser'#'localhost':
GRANT ALL PRIVILEGES ON `db1`.* TO 'myuser'#'localhost';
GRANT ALL PRIVILEGES ON `db2_beta`.* TO 'myuser'#'localhost';
Otherwise the anonymous user #localhost created during db install takes precedence among your user with the wildcard hostname (%), as described here:
http://dev.mysql.com/doc/refman/5.5/en/adding-users.html
According to the mysql manual here:
If you modify the grant tables indirectly using account-management
statements such as GRANT, REVOKE, or SET PASSWORD, the server notices
these changes and loads the grant tables into memory again
immediately.
If you modify the grant tables directly using statements such as
INSERT, UPDATE, or DELETE, your changes have no effect on privilege
checking until you either restart the server or tell it to reload the
tables. If you change the grant tables directly but forget to reload
them, your changes have no effect until you restart the server. This
may leave you wondering why your changes do not seem to make any
difference!
This does seem to be true in most cases. However, in my situation I was working with an Amazon Web Services (AWS) RDS mysql instance. After many unsuccessful attempts to grant the user permissions I tried a FLUSH PRIVILEGES and the database was immediately visible to the user. If you come across this while looking for a solution on the Amazon Web Services RDS platform you might want to give this a try and see if it helps.
This SO question contains the most complete solutions to this problem and is the first in most search results so I wanted to add this response for anyone using RDS. Hopefully it will save RDS admins some time.
I have run into the same problem in the past. Have you tried the following?
GRANT ALL ON `db1`.* TO 'myuser'#'%' IDENTIFIED BY PASSWORD '*7733323232...';
GRANT ALL ON `db2`.* TO 'myuser'#'%' IDENTIFIED BY PASSWORD '*7733323232...';
FLUSH PRIVILEGES;
I've created database, for example 'mydb'.
CREATE DATABASE mydb CHARACTER SET utf8 COLLATE utf8_bin;
CREATE USER 'myuser'#'%' IDENTIFIED BY PASSWORD '*HASH';
GRANT ALL ON mydb.* TO 'myuser'#'%';
GRANT ALL ON mydb TO 'myuser'#'%';
GRANT CREATE ON mydb TO 'myuser'#'%';
FLUSH PRIVILEGES;
Now i can login to database from everywhere, but can't create tables.
How to grant all privileges on that database and (in the future) tables. I can't create tables in 'mydb' database. I always get:
CREATE TABLE t (c CHAR(20) CHARACTER SET utf8 COLLATE utf8_bin);
ERROR 1142 (42000): CREATE command denied to user 'myuser'#'...' for table 't'
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'#'%' WITH GRANT OPTION;
This is how I create my "Super User" privileges (although I would normally specify a host).
IMPORTANT NOTE
While this answer can solve the problem of access, WITH GRANT OPTION creates a MySQL user that can edit the permissions of other users.
The GRANT OPTION privilege enables you to give to other users or remove from other users those privileges that you yourself possess.
For security reasons, you should not use this type of user account for any process that the public will have access to (i.e. a website). It is recommended that you create a user with only database privileges for that kind of use.
This is old question but I don't think the accepted answer is safe. It's good for creating a super user but not good if you want to grant privileges on a single database.
grant all privileges on mydb.* to myuser#'%' identified by 'mypasswd';
grant all privileges on mydb.* to myuser#localhost identified by 'mypasswd';
% seems to not cover socket communications, that the localhost is for. WITH GRANT OPTION is only good for the super user, otherwise it is usually a security risk.
Update for MySQL 5.7+ seems like this warns about:
Using GRANT statement to modify existing user's properties other than
privileges is deprecated and will be removed in future release. Use
ALTER USER statement for this operation.
So setting password should be with separate commands. Thanks to comment from #scary-wombat.
ALTER USER 'myuser'#'%' IDENTIFIED BY 'mypassword';
ALTER USER 'myuser'#'localhost' IDENTIFIED BY 'mypassword';
This will be helpful for some people:
From MySQL command line:
CREATE USER 'newuser'#'localhost' IDENTIFIED BY 'password';
Sadly, at this point newuser has no permissions to do anything with the databases. In fact, if newuser even tries to login (with the password, password), they will not be able to reach the MySQL shell.
Therefore, the first thing to do is to provide the user with access to the information they will need.
GRANT ALL PRIVILEGES ON * . * TO 'newuser'#'localhost';
The asterisks in this command refer to the database and table (respectively) that they can access—this specific command allows to the user to read, edit, execute and perform all tasks across all the databases and tables.
Once you have finalized the permissions that you want to set up for your new users, always be sure to reload all the privileges.
FLUSH PRIVILEGES;
Your changes will now be in effect.
For more information: http://dev.mysql.com/doc/refman/5.6/en/grant.html
If you are not comfortable with the command line then you can use a client like MySQL workbench, Navicat or SQLyog
1. Create the database
CREATE DATABASE db_name;
2. Create the username for the database db_name
GRANT ALL PRIVILEGES ON db_name.* TO 'username'#'localhost' IDENTIFIED BY 'password';
3. Use the database
USE db_name;
4. Finally you are in database db_name and then execute the commands like create , select and insert operations.
This SQL grants on all databases but just basic privileges. They're enough for Drupal or Wordpress and as a nicety, allows one developer account for local projects.
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP,
INDEX, ALTER, CREATE TEMPORARY TABLES
ON *.* TO 'username'#'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON mydb.* TO myuser#localhost IDENTIFIED BY 'mypasswd';
Works for privileges on schema :)
Optional: after mypasswd you can add WITH GRANT OPTION
I could able to make it work only by adding GRANT OPTION, without that always receive permission denied error
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'#'localhost' WITH GRANT OPTION;
Hello I used this code to have the super user in mysql
GRANT EXECUTE, PROCESS, SELECT, SHOW DATABASES, SHOW VIEW, ALTER, ALTER ROUTINE,
CREATE, CREATE ROUTINE, CREATE TEMPORARY TABLES, CREATE VIEW, DELETE, DROP,
EVENT, INDEX, INSERT, REFERENCES, TRIGGER, UPDATE, CREATE USER, FILE,
LOCK TABLES, RELOAD, REPLICATION CLIENT, REPLICATION SLAVE, SHUTDOWN,
SUPER
ON *.* TO mysql#'%'
WITH GRANT OPTION;
and then
FLUSH PRIVILEGES;
I had this challenge when working on MySQL Ver 8.0.21
I wanted to grant permissions of a database named my_app_db to the root user running on localhost host.
But when I run the command:
use my_app_db;
GRANT ALL PRIVILEGES ON my_app_db.* TO 'root'#'localhost';
I get the error:
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'my_app_db.* TO 'root'#'localhost'' at line 1>
Here's how I fixed:
Login to your MySQL console. You can change root to the user you want to login with:
mysql -u root -p
Enter your mysql root password
Next, list out all the users and their host on the MySQL server. Unlike PostgreSQL this is often stored in the mysql database. So we need to select the mysql database first:
use mysql;
SELECT user, host FROM user;
Note: if you don't run the use mysql, you get the no database selected error.
This should give you an output of this sort:
+------------------+-----------+
| user | host |
+------------------+-----------+
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+------------------+-----------+
4 rows in set (0.00 sec)
Next, based on the information gotten from the list, grant privileges to the user that you want. We will need to first select the database before granting permission to it. For me, I am using the root user that runs on the localhost host:
use my_app_db;
GRANT ALL PRIVILEGES ON *.* TO 'root'#'localhost';
Note: The GRANT ALL PRIVILEGES ON database_name.* TO 'root'#'localhost'; command may not work for modern versions of MySQL. Most modern versions of MyQL replace the database_name with * in the grant privileges command after you select the database that you want to use.
You can then exit the MySQL console:
exit
That's it.
I hope this helps
To access from remote server to mydb database only
GRANT ALL PRIVILEGES ON mydb.* TO 'root'#'192.168.2.21';
To access from remote server to all databases.
GRANT ALL PRIVILEGES ON * . * TO 'root'#'192.168.2.21';
To grant all priveleges on the database: mydb to the user: myuser, just execute:
GRANT ALL ON mydb.* TO 'myuser'#'localhost';
or:
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'#'localhost';
The PRIVILEGES keyword is not necessary.
Also I do not know why the other answers suggest that the IDENTIFIED BY 'password' be put on the end of the command. I believe that it is not required.