I'm running mysql workbench on my 2011 macbook pro. I use it to connect to a mysql database on a remote ubuntu server. I was able to connect no problem from my macbook pro to the mysql database on the remote server until I had to do a hard reboot on my mac. After that I would get the error below.
However once I port forwarded with the command below on my mac for the specified user it connects to the database on the remote server with mysql workbench no problem. What does this tell us about the issue connecting from my mac to the database on the remote server? I would rather not portforward for every user I want to login with from my mac. Does anyone have a suggestion how to fix this?
command:
ssh -N -f -L localhost:3306:localhost:3306 username#192.168.50.122
previous error:
Failed to connect to MySQL at xxx.xxx.xx.xxx:3306 with user username Access denied for user 'username'#'xxx.xxx.xx.xxx' (using password: YES)
Update:
When I try looking up the grants for the username with the ip address I'm not finding them and getting the error message below. When I try to look up the sql_show_grants table I get another error message. When I try looking up the same username with '%' I'm finding all the grants below. So does it make sense that the user still can't connect from any ip? Is there something else I need to do?
show grants for 'username'#'xxx.xxx.xx.xxx';
ERROR 1141 (42000): There is no such grant defined for user 'username' on host 'xxx.xxx.xx.xxx'
SELECT sql_grants FROM common_schema.sql_show_grants;
ERROR 1049 (42000): Unknown database 'common_schema'
show grants for 'username'#'%';
+--------------------------------------------------------------+
| Grants for username#% |
+--------------------------------------------------------------+
| GRANT USAGE ON *.* TO `username`#`%` |
| GRANT ALL PRIVILEGES ON `finances`.* TO `username`#`%` |
| GRANT ALL PRIVILEGES ON `geographical`.* TO `username`#`%` |
| GRANT ALL PRIVILEGES ON `realestate`.* TO `username`#`%` |
| GRANT ALL PRIVILEGES ON `sandbox`.* TO `username`#`%` |
| GRANT ALL PRIVILEGES ON `stocks`.* TO `username`#`%` |
+--------------------------------------------------------------+
The account you are trying to connect with does not have permission to access the server from your clients IP address. If you use SSH port forwarding, you are being connected from localhost (from the server to the server), and hence get a different permission scheme applied.
On the MySQL server, start a mysql shell as an administrator, and run
SHOW GRANTS FOR 'username'#'xxx.xxx.xx.xxx'
(replacing 'username'#'xxx.xxx.xx.xxx' with what it showed you in the error message).
If it does not show any results, your user does not have any permissions from the respective IP address, and you would need to alter or create it.
If it does show permissions, make sure SELECT is underneath them.
If you cannot locate your user, attempt to view all grants:
SELECT sql_grants FROM common_schema.sql_show_grants;
If you say it worked before, it is possible that the original user was added with a dynamic IP address, which changed after the reboot of your client.
If this is the case, and the last statement shows your user with a wrong IP address, use the following to update it:
RENAME USER 'username'#'ipaddress1' TO 'username'#'ipaddress2';
You might want to consider using '%' instead of 'ipaddress2', if you are using dynamic IP addresses and want to grant the user access from all source addresses. Whether this is a security issue, depends on your environment.
I have created a MariaDB database user user. Looks something like:
MariaDB [(none)]> select host,user,password from mysql.user;
+-----------+-------+-------------------------------------------+
| host | user | password |
+-----------+-------+-------------------------------------------+
| % | user | ***************************************** |
+-----------+-------+-------------------------------------------+
I can connect to the database from a remote computer using command like
mysql -uuser -hdevops.ok -p mydatabase
This works as expected. I can login using my password.
When I am on the database server and try to connect with
[vagrant#devops ~]$ mysql -h127.0.0.1 -uuser -p mydatabase
Enter password:
ERROR 1045 (28000): Access denied for user 'user'#'localhost' (using password: YES)
I expected the % to allow access from all nodes in the network including localhost but it seems this is not how it works.
Is it possible to grant this user local access?
I can create another account of course
create user 'myser'#'localhost' identified by '****';
This would allow me access to the database but that feels more like a workaround.
Update
I now think this is only possible by creating two accounts 'myuser'#'localhost' and 'myuser'#'%'
% does not include localhost. Btw 127.0.0.1 and 127.0.0.2 resolve to localhost and as a consequence these are also not matches by %.
Doesn't make sense but it looks like this is the way it is supposed to work.
The % in the host field means any targeted host is possible.
There is one special case, when the database makes a difference between 127.0.0.1 (TCP based connection) and localhost which connects to the local unix socket.
Consider the db settings skip-networking and bind-address. See
https://mariadb.com/kb/en/mariadb/configuring-mariadb-for-remote-client-access/
TCP connections are usually disabled by default - this might be different depending on distribution, package used, ...
So when you type the following it should work:
mysql -hlocalhost -uuser -p mydatabase
References:
https://dev.mysql.com/doc/refman/5.5/en/connecting.html
On Unix, MySQL programs treat the host name localhost specially, in a way that is likely different from what you expect compared to other network-based programs. For connections to localhost, MySQL programs attempt to connect to the local server by using a Unix socket file.
You could also use the --socket option.
I am troubleshooting a MySQL privileges problem.
I want to connect to MySQL on the local server, but refer to it by it's LAN name (so I can use the same user/pass/host on several web-nodes).
I have included credentials in the privilege tables for both a %.lan and a localhost user.
mysql> select user,host from mysql.user where user = 'mysqluser';
+-----------+---------------------+
| user | host |
+-----------+---------------------+
| mysqluser | %.lan |
| mysqluser | localhost |
+-----------+---------------------+
However, when I try to login, I get the error message
[systemuser#servername.mydomain.com ~]$ mysql -u mysqluser -p -h servername.mydomain.com.lan
Access denied for user 'mysqluser'#'servername.mydomain.com'
Note that servername.mydomain.com.lan does resolve to a 192.168.% IP; i.e. it's in my /etc/hosts file. Moreover, reverse DNS for the IP in question resolves as expected.
[systemuser#servername.mydomain.com ~]$ dig -x 192.168.X.Y
...
;; ANSWER SECTION:
Y.X.168.192.in-addr.arpa. 86400 IN PTR servername.mydomain.com.lan.
If I temporarily grant privileges to 'mysqluser'#'%' and login, MySQL reports
mysql> status
...
Current user: mysqluser#servername.mydomain.com
...
Connection: servername.mydomain.com.lan via TCP/IP
...
Why is the host for my Current user not equal to the host for my Connection?
What I am doing/assuming incorrectly? I should note that my arrangement was working as intended (for weeks), on two farms on a common LAN, then both, independent MySQL instances suddenly started rejecting MySQL connections.
I have 2 different server, one server (server1) hosts the perl application and the other server (server2) hosts the MYSQL DB (DBNAME= hpdb).
The perl application on server1 is suppose to get mysql results from server2. When I try to do this I get the error message Access denied for user 'userrego'#'server1.domain.com' (using password: YES).
However, when I host the perl application on server2, the application works as expected.
I tried to GRANT ALL PRIVILEGES ON hpdb.* TO 'userrego'#'server1.domain.com' but still couldn't get it to work.
mysql> SHOW GRANTS FOR 'userrego'#'server1.domain.com';
+---------------------------------------------------------------------+
| Grants for userrego#server1.domain.com |
+---------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'userrego'#'server1.domain.com' |
| GRANT ALL PRIVILEGES ON `hpdb`.* TO 'userrego'#'server1.domain.com' |
+---------------------------------------------------------------------+
2 rows in set (0.01 sec)
There are a couple of things you should please verify:
Please make sure skip-networking in my.cnf is disabled. If bind-address is set, make sure it is appropriately set, depending on the network config of server2. Do a service mysql restart if you changed anything.
If it still does not work I would verify that the password and source ip is not the issue by (if possible) creating another user to connect with - you can always remove it after testing. Issue a grant with:
GRANT ALL PRIVILEGES ON hpdb.* TO 'userregotest'#'%' IDENTIFIED BY 'xxxxxx'
With that you will be sure of the correct password and that the source ip address is not the issue since any source address will be able to connect.
If none of this works, we might need to inspect things a bit closer.
My MySQL database needs two users: appuser and support.
One of the application developers insists that I create four accounts for these users:
appuser#'%'
appuser#'localhost'
support#'%'
support#'localhost'
For the life of me I can't figure out why he thinks we need this. Wouldn't using the wildcard as the host take care of the 'localhost'?
Any ideas?
(Using MySQL 5.5 here)
localhost is special in MySQL, it means a connection over a UNIX socket (or named pipes on Windows, I believe) as opposed to a TCP/IP socket. Using % as the host does not include localhost, hence the need to explicitly specify it.
As #nos pointed out in the comments of the currently accepted answer to this question, the accepted answer is incorrect.
Yes, there IS a difference between using % and localhost for the user account host when connecting via a socket connect instead of a standard TCP/IP connect.
A host value of % does not include localhost for sockets and thus must be specified if you want to connect using that method.
Let's just test.
Connect as superuser, and then:
SHOW VARIABLES LIKE "%version%";
+-------------------------+------------------------------+
| Variable_name | Value |
+-------------------------+------------------------------+
| version | 10.0.23-MariaDB-0+deb8u1-log |
and then
USE mysql;
Setup
Create a user foo with password bar for testing:
CREATE USER foo#'%' IDENTIFIED BY 'bar'; FLUSH PRIVILEGES;
Connect
To connect to the Unix Domain Socket (i.e. the I/O pipe that is named by the filesystem entry /var/run/mysqld/mysqld.sock or some such), run this on the command line (use the --protocol option to make doubly sure)
mysql -pbar -ufoo
mysql -pbar -ufoo --protocol=SOCKET
One expects that the above matches "user comes from localhost" but certainly not "user comes from 127.0.0.1".
To connect to the server from "127.0.0.1" instead, run this on the command line
mysql -pbar -ufoo --bind-address=127.0.0.1 --protocol=TCP
If you leave out --protocol=TCP, the mysql command will still try to use the Unix domain socket. You can also say:
mysql -pbar -ufoo --bind-address=127.0.0.1 --host=127.0.0.1
The two connection attempts in one line:
export MYSQL_PWD=bar; \
mysql -ufoo --protocol=SOCKET --execute="SELECT 1"; \
mysql -ufoo --bind-address=127.0.0.1 --host=127.0.0.1 --execute="SELECT 1"
(the password is set in the environment so that it is passed to the mysql process)
Verification In Case Of Doubt
To really check whether the connection goes via a TCP/IP socket or a Unix Domain socket
get the PID of the mysql client process by examining the output of ps faux
run lsof -n -p<yourpid>.
You will see something like:
mysql [PID] quux 3u IPv4 [code] 0t0 TCP 127.0.0.1:[port]->127.0.0.1:mysql (ESTABLISHED)
or
mysql [PID] quux 3u unix [code] 0t0 [code] socket
So:
Case 0: Host = '10.10.10.10' (null test)
update user set host='10.10.10.10' where user='foo'; flush privileges;
Connect using socket: FAILURE
Connect from 127.0.0.1: FAILURE
Case 1: Host = '%'
update user set host='%' where user='foo'; flush privileges;
Connect using socket: OK
Connect from 127.0.0.1: OK
Case 2: Host = 'localhost'
update user set host='localhost' where user='foo';flush privileges;
Behaviour varies and this apparently depends on skip-name-resolve. If set, causes lines with localhost to be ignored according to the log. The following can be seen in the error log: "'user' entry 'root#localhost' ignored in --skip-name-resolve mode.". This means no connecting through the Unix Domain Socket. But this is empirically not the case. localhost now means ONLY the Unix Domain Socket, and no longer matched 127.0.0.1.
skip-name-resolve is off:
Connect using socket: OK
Connect from 127.0.0.1: OK
skip-name-resolve is on:
Connect using socket: OK
Connect from 127.0.0.1: FAILURE
Case 3: Host = '127.0.0.1'
update user set host='127.0.0.1' where user='foo';flush privileges;
Connect using socket: FAILURE
Connect from 127.0.0.1: OK
Case 4: Host = ''
update user set host='' where user='foo';flush privileges;
Connect using socket: OK
Connect from 127.0.0.1: OK
(According to MySQL 5.7: 6.2.4 Access Control, Stage 1: Connection Verification, The empty string '' also means “any host” but sorts after '%'. )
Case 5: Host = '192.168.0.1' (extra test)
('192.168.0.1' is one of my machine's IP addresses, change appropriately in your case)
update user set host='192.168.0.1' where user='foo';flush privileges;
Connect using socket: FAILURE
Connect from 127.0.0.1: FAILURE
but
Connect using mysql -pbar -ufoo -h192.168.0.1: OK (!)
The latter because this is actually TCP connection coming from 192.168.0.1, as revealed by lsof:
TCP 192.168.0.1:37059->192.168.0.1:mysql (ESTABLISHED)
Edge Case A: Host = '0.0.0.0'
update user set host='0.0.0.0' where user='foo';flush privileges;
Connect using socket: FAILURE
Connect from 127.0.0.1: FAILURE
Edge Case B: Host = '255.255.255.255'
update user set host='255.255.255.255' where user='foo';flush privileges;
Connect using socket: FAILURE
Connect from 127.0.0.1: FAILURE
Edge Case C: Host = '127.0.0.2'
(127.0.0.2 is perfectly valid loopback address equivalent to 127.0.0.1 as defined in RFC6890)
update user set host='127.0.0.2' where user='foo';flush privileges;
Connect using socket: FAILURE
Connect from 127.0.0.1: FAILURE
Interestingly:
mysql -pbar -ufoo -h127.0.0.2 connects from 127.0.0.1 and is FAILURE
mysql -pbar -ufoo -h127.0.0.2 --bind-address=127.0.0.2 is OK
Cleanup
delete from user where user='foo';flush privileges;
Addendum
To see what is actually in the mysql.user table, which is one of the permission tables, use:
SELECT SUBSTR(password,1,6) as password, user, host,
Super_priv AS su,
Grant_priv as gr,
CONCAT(Select_priv, Lock_tables_priv) AS selock,
CONCAT(Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv) AS modif,
CONCAT(References_priv, Index_priv, Alter_priv) AS ria,
CONCAT(Create_tmp_table_priv, Create_view_priv, Show_view_priv) AS views,
CONCAT(Create_routine_priv, Alter_routine_priv, Execute_priv, Event_priv, Trigger_priv) AS funcs,
CONCAT(Repl_slave_priv, Repl_client_priv) AS replic,
CONCAT(Shutdown_priv, Process_priv, File_priv, Show_db_priv, Reload_priv, Create_user_priv) AS admin
FROM user ORDER BY user, host;
this gives:
+----------+----------+-----------+----+----+--------+-------+-----+-------+-------+--------+--------+
| password | user | host | su | gr | selock | modif | ria | views | funcs | replic | admin |
+----------+----------+-----------+----+----+--------+-------+-----+-------+-------+--------+--------+
| *E8D46 | foo | | N | N | NN | NNNNN | NNN | NNN | NNNNN | NN | NNNNNN |
Similarly for table mysql.db:
SELECT host,db,user,
Grant_priv as gr,
CONCAT(Select_priv, Lock_tables_priv) AS selock,
CONCAT(Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv) AS modif,
CONCAT(References_priv, Index_priv, Alter_priv) AS ria,
CONCAT(Create_tmp_table_priv, Create_view_priv, Show_view_priv) AS views,
CONCAT(Create_routine_priv, Alter_routine_priv, Execute_priv) AS funcs
FROM db ORDER BY user, db, host;
If you want connect to user#'%' from localhost use mysql -h192.168.0.1 -uuser -p.
The percent symbol means: any host, including remote and local connections.
The localhost allows only local connections.
(so to start off, if you don't need remote connections to your database, you can get rid of the appuser#'%' user right away)
So, yes, they are overlapping, but...
...there is a reason for setting both types of accounts, this is explained in the mysql docs:
http://dev.mysql.com/doc/refman/5.7/en/adding-users.html.
If you have an have an anonymous user on your localhost, which you can spot with:
select Host from mysql.user where User='' and Host='localhost';
and if you just create the user appuser#'%' (and you not the appuser#'localhost'), then when the appuser mysql user
connects from the local host, the anonymous user account is used (it has precedence over your appuser#'%' user).
And the fix for this is (as one can guess) to create the appuser#'localhost' (which is more specific that the local host anonymous user and will be used if your appuser connects from the localhost).
Going to provide a slightly different answer to those provided so far.
If you have a row for an anonymous user from localhost in your users table ''#'localhost' then this will be treated as more specific than your user with wildcard'd host 'user'#'%'. This is why it is necessary to also provide 'user'#'localhost'.
You can see this explained in more detail at the bottom of this page.