How does mysql do reverse resolution of IP addresses? - mysql

We rebooted a machine running mysql, and we're having some odd issues. Most processes from other machines are able to connect to without issue. We can also connect locally if we connect through the loopback address explicitly.
This works:
mysql -hlocalhost -utest_user -psecret_password
When we run the command:
mysql -h192.168.1.10 -utest_user -psecret_password
locally on the machine we get the following error:
ERROR 1045 (28000): Access denied for user `test_user`#`SERVER_123`
We had the following users:
test_user#localhost
test_user#%
We have fixed the issue by adding the following user:
test_user#SERVER_123
Where SERVER_123 is the unqualified name of the machine.
We don't know why we had to add that additional user, and we don't want to keep it, but we also don't know why adding it fixed the issue.
Why does connecting from the local machine, via IP (i.e. mysql -ha.b.c.d -utest_user -ppsswd) fail to match the test_user#% user, but will match test_user#machine_name, where machine_name is the unqualified name of the machine?
Here is the user table
anonymous %
anonymous SERVER_123
anonymous localhost
test_user_2 %
test_user_3 %
root ::1
root 127.0.0.1
root SERVER_123
root localhost
Note: Figured out the issue. Somehow rebooting the machine must have changed how 192.168.1.10 resolved so that it resolved to SERVER_123. That then caused logins from 192.168.1.10 to match test_user#SERVER_123.

I would take a look at the sorting rules in this section of the MySQL documentation: https://dev.mysql.com/doc/refman/5.7/en/connection-access.html
It is possible for the client host name and user name of an incoming connection to match more than one row in the user table.
It could be that your user is identified as another user with a different password. What other entries are present in your user table?
Update based on new information: Your login was identified as the ''#'%' user. This user either has different credentials, or is missing the necessary permissions.

You can follow the MySQL documentation here, which talks about the DNS lookup optimization and also the process how this is achieved. To point out one point from the documentation is the following:
The MySQL server maintains a host cache in memory that contains information about clients: IP address, host name, and error information. The server uses this cache for nonlocal TCP connections. It does not use the cache for TCP connections established using a loopback interface address (127.0.0.1 or ::1), or for connections established using a Unix socket file, named pipe, or shared memory.
And there is another point that help you resolve this is with the introduction of the following parameter:
skip-name-resolve
You can follow the article here that suggests that MySQL authenticates based on IP addresses or Hostnames - Article link here.
By default MySQL grants authentication on users based on IP address or hostnames. When there is a connection from a particular host, MySQL does a reverse DNS lookup and compares the hostname and IP address.
Hope this helps to answer your question!

First of all remember only 127.0.0.1, ::1, localhost etc... are considered as loopback addresses not 192.168.1.10 or SERVER_123 as you may be accepting.
Yes! 192.168.1.10 should match for wildcard host %, but unfortunately beside test_user_2 and test_user_3 I don't see test_user entry in provided user table data.
In addition on Linux you may use /etc/hosts file to map ip address to hostname

Found the issue. There is an anonymous user which is matching before the specific user. I'm not sure what happened during the reboot that caused reverse resolution to change, but we had a user ''#'SERVER_123' which must have started matching. Removing the anonymous user fixed the issue, and we no longer need to have privileges for test_user#SERVER_123.

Related

How to access a MySQL server hosted on a Virtual Machine using another Virtual Machine?

I have created 2 Ubuntu 20.04 VMs using VirtualBox. I have a Django App on one VM and MySQL DB on the other VM. How do I access the MySQL DB using the first VM?
I used the inet from the output of ifconfig for the IP Address
What I tried:
On the VM having MySQL DB:
-> Change the 'bind_adress' field to '0.0.0.0' in '/etc/mysql/mysql.conf.d/mysqld.cnf'
-> Created a new user using CREATE USER 'test'#'IP_Address1' IDENTIFIED BY 'password';
-> Ran "sudo ufw allow from IP_Address1 to any port 3306"
On the VM having the Django App:
-> Tried to connect to the Virtual Machine using mysql -u 'test' -h 'IP_ADDRESS2' -p
The error I'm getting:
"Unknown MySQL host 'address'"
PS:
I created a NAT network on VirtualBox using File->Preference->Network and attached both the VMs to the network and set Promiscuous Mode to "Allow All"
How or where are you defining IP_Address1 and IP_ADDRESS2?
Specifically, your DB machine needs to know what the IP address of the client machine is when you use your CREATE USER query. So, IP_Address1 must be "known" to that machine. Maybe you just hid the IP address when you posted the question, but it might be easier to use actual IP addresses in both cases until you get connectivity.
For example, if your DB machine is 172.18.1.1 and your client machine is 172.18.1.2, then you should use those IP addresses in your commands listed above
Created a new user using
"CREATE USER 'test'#'172.18.1.2' IDENTIFIED BY 'password';"
...here you're defining the IP address of the client connection.
Then in the client machine:
"mysql -u 'test' -h '172.18.1.1' -p"
...here, telling the client the IP address of the DB machine
More importantly, you might also have to expose the DB to the local network in its configuration settings. You'll also have to deal with any routing issues if the two machines are not on the same local subnet.
There are several articles describing how to configure MySQL for network access, such as: https://www.digitalocean.com/community/tutorials/how-to-allow-remote-access-to-mysql
What have you tried? Can you connect from the command line on the .5 machine? There's a mysql command line tool you can use to connect, which might give you some more information, or have you looked at the MySQL logs to see what it's unhappy about?
It could be something like a permissions issue for the user - creating a user alone is not enough to allow them access to database resources. Maybe try something like:
GRANT ALL ON Database.* TO test#'172.25.1.5' IDENTIFIED BY 'PASSWORD';
I was assuming you had configured the various permissions on the database and were only seeing connectivity issues, but from your responses, it's not clear.
Basically, you need to isolate whether the problem is a user permission issue, an IP restriction issue, a VM issue, a coding issue with your app or something else.
Please provide more feedback about what you've tried if you're still struggling, but this could be one of a number of issues.

Is there a reason localhost and hostname have no user in tabel user?

I have in the user table two rows where user name and password are empty, host is localhost and my hostname. The privileges are all set to none. This configuration allows the user to start mysql just with entering mysql, but you can't do anything.
Is this a good configuration? I can't remember adding these rows in the table, and now I am really in doubt if these rows should be there. In the manual of MySQL and MadiaDB, I am unable to find my answer.
These are so-called anonymous users and are described in the mysql manual on default privileges, meaning that these accounts are added by the installer by default:
If accounts for anonymous users were created, these have an empty user
name. The anonymous accounts have no password, so anyone can use them
to connect to the MySQL server.
On Windows, there is one anonymous account that permits connections
from the local host. Connections can be made by specifying a host name
of localhost.
On Unix, each anonymous account permits connections from the local
host. Connections can be made by specifying a host name of localhost
for one of the accounts, or the actual host name or IP address for the
other.
If you do not need them, you better remove them, or as a minimum, assign password to these accounts.

mysql - Inability to connect using procedure that has been in place for years

I use a procedure during tax season to connect from a script on my workstation to a production mysql server. The procedure has been in use since 2007. This year I am unable to connect to the mysql server, getting "access denied for user 'xxx'#'localhost'". The command line is as follows:
mysql -u xxx -p -h ourmysqlserver
where "xxx" and "ourmysqlserver" are dummy names used for this question.
When I ping ourmysqlserver, it resolves to the expected IP on our VPN.
I would not expect 'xxx'#'localhost' to be able to connect, as there are no grants for 'xxx'#'localhost' because it is not appropriate. Rather we have always used 'xxx'#'10.8.0.%', where the 10.8.0 network is our VPN. It does not make sense to me have have localhost because that either implies I am coming in from an account on mysqlserver, or I am trying to connect to a local instance of mysql, neither of which I am trying to do.
On a hunch, I entered GRANTS for 'xxx'#'localhost'. You would think that that would then work. But that does not work either.
While this procedure has been in place a long time, over the years our DNS, VPN, mysql server, mysql client, and host server configurations have changed.
I am suspecting that there is something in the configuration of the mysql client that is forcing it to act in an unexpected way. But I would like to resolve this so as to be able to continue using existing procedures.
EDIT: I discovered that by switching the -h parameter to an IP address instead of a DNS name, that the connection can be made. It is still a mystery why the DNS name cannot be used in some place (it still works fine elsewhere) and why 'localhost' appears in the error message.
My immediate guess would be a dns vs hosts file issue. I may be that with the hosts file, it is resolving to the loopback adaptor and then when you try to do a reverse dns lookup, it comes back as localhost.
In other words, my guess is that this is what happens:
host ourmysqlserver probably resolves locally to 127.0.0.1
127.0.0.1 resolves to localhost via reverse dns
the ip address resolves to the correct hostname via reverse dns
The problem is probably in /etc/hosts

determining the IP from which an mysql connect (PDO) request came from

I want one Linux server to get or put data to the MySQL server on another Linux machine. I want to avoid granting
GRANT ALL PRIVILEGES ON *.* TO root#% IDENTIFIED BY 'password';
but instead would like to do:
GRANT ALL PRIVILEGES ON *.* to root#123.123.123.123 ..
where 123.. is the IP of the server that is making the request. Where would I go to get a log of the request made on the receiving database end, to know what IP is being queried from? I don't know enough about networking to know this, or to be sure which IP is being used.
Also, would it be OK to use a hostname of the querying server, or is that slower due to DNS lookup time?
If you want to know what IP you're connecting from:
SHOW PROCESSLIST
This will show the originating IP. You can tighten your rules accordingly.
As per my comment to #tadman, the problem turned out to be that I had
bind = 127.0.0.1
in the my.conf file found in /etc/mysql.
Well, once I disabled and restarted mysql, mysql came back and said "permission denied to root#____" - but then I was able to know the IP address. Predictably I guess, it was the primary DNS IP for that server. But problem solved because I was able to set that permission on the remote.

Problem connecting to external mysql database

My problem is this command produces an error when I tried to connect from our server to another external server :
mysql -h db.hostname.com -u username -pP#ssword database_name
And this is the error :
ERROR 1044 (42000): Access denied for user 'username'#'%' to database 'database_name'
I already asked the external server admin to add our IP in their firewall but to no avail..
Has this something to do with GRANTing privileges to the 'username'
It's not a problem with firewall, since MySQL is denying the connection. As you suspect, it is a problem with the privileges granted for the user. You need to execute this on the mysql server (you might need to tweak this a bit if you don't want to grant all privileges to the db):
GRANT ALL ON database_name.* TO 'username'#'%' IDENTIFIED BY 'P#ssword';
Also note that if you always connect from a specific host/ip, it's a better idea to specify that host/ip, instead of using a wildcard %, which would allow connections from anywhere.
It sounds like the password is wrong, or that the username you are trying to use is not allowed to connect from your computer's IP address.
as you know, the mysql administrator at the remote site can specify which IP's are allowed to connect using any given user account. Bear in mind that your computer's IP address may be routed through all kinds of routers and firewalls on your company's end before you reach the external database. As a result, your IP may appear different to you than to the external database.
In that case, it doesn't help if the external database admin adds YOUR IP to the 'allowed' list, they should add the 'outside world' IP address instead.
The easiest way to find out if this applies to you, is as follows:
visit www.whatismyip.com and write down the IP address on screen. This is your IP as seen from the 'outside world'. It is very likely that this IP is actually the outside IP of a firewall or router within your company's network, and not your computer's IP at all.
Next, (assuming you're on Windows) go to Start > run. Type cmd and hit enter. Type ipconfig and hit enter. You can now see your local IP address.
If these two IP's don't match, tell the remote admin to add your outside world IP to the 'allowed' list as well.
also - once you go to production, and move your code to another server, the IP fun starts again. You might as well fix this right away