In this article, we will demonstrate how to have a single MySQL database user account that can connect from specific hosts.

We would usually implement it by creating separate user accounts with the same username but different hosts/IPs like <USER>@<HOST1>, <USER>@<HOST2> …. <USER>@<HOSTn>. Then, give those users the same grants(privileges/roles) and settings(password, SSL, etc).

Instead of doing such, we will create a single user (‘’@’%’) that can connect from all hosts and then use the init_connect server parameter to call a procedure that would implement the host restriction for a user. This will make managing user account settings and privileges easier as we only need to apply it to one database user account.

Process

Client hostname and IP:

Create the schema with a table containing the host allow list. The table will be used to check with the output of the USER() function.

Create the stored procedure that would implement the host restriction for users that have a value host = ‘%’ (from CURRENT_USER()) and is found in the allow_list table (base from USER()).

Set init_connect server parameter.

Add to my.cnf to persist upon restart.

Note: We call the function CURRENT_USER() outside the procedure as calling it inside will give the value of the procedure definer and not the currently connected user.

Create database users.

Grant database-level EXECUTE privilege because recreating(DROP then CREATE) the PROCEDURE will cause the grants given on that specific PROCEDURE to be lost.

Add to our mysql server /etc/hosts. If you have a DNS server, you may add the host to it instead.

Note: If you made changes to your host file or DNS for an IP that already has a HOST value in the performance_schema.host_cache table, you must do a FLUSH HOSTS.

Test connection for ‘app1’@’%’.

Since we still don’t have entries in the allow_list table, we should expect our connection to fail.

From c7-171(192.168.122.171).

From c7-172(192.168.122.172).

Check the error log. Note that the log below needs a log_error_verbosity value of two or three.

We see that processlist/connection id 12 and 13 got an aborted connection. It was caused by the init_connect parameter failure. It indicates from what host the failed connection happens and the custom error message through the SIGNAL command in the stored procedure.

Let us allow connection from those hosts: c7-171(via IP) and c7-172(via Hostname).

Now, the connection from c7-171 succeeds.

Same success with c7-172.

Test connection for second user ‘app2’@’192.%’.

From c7-171(192.168.122.171).

Authenticated user ‘app2’@’192.%’ did not fail even if ‘app2’@’192.168.122.171’ does not exist in the allow_list table because its authenticated host(’192.%’ ) is not equal to ‘%.’

Considerations

  • Init_connect content is not executed for users admin users.
  • It will not work as expected if the application connects to a connection pooler like ProxySQL, where the database(backend) connections are reused/shared by the other ProxySQL frontend connections.
  • If skip_name_resolve is enabled, be sure to use IP and not hostname in the allow_list table.
  • Please consider using ROLE if the init_connect approach is not applicable to your requirements. This will simplify the granting of privileges to a single role and then grant the role to multiple user accounts with a specific host.
  • A write lock to the allow_list table (LOCK TABLES allow_list WRITE) will cause the initial login to hang. Please avoid it or do not use allow_list table but rather do some logic in the procedure to use a list of user and host hardcoded in the procedure.

Conclusion

We can create a single database account (@’%’) to help simplify user management, and with the additional help from the init_connect parameter, we can restrict it to specific hosts. The above example might not fit your requirements, so you will have to adjust accordingly and conduct a rigorous test.


MySQL Performance Tuning is an essential eBook covering the critical aspects of MySQL performance optimization.

Download and unlock the full potential of your MySQL database today!

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments