Would it be sensible to create a MySQL user for each user account of a web application?

What type of logging would you be looking at gaining? What I do in my application is an audit table that tracks application user, application command, and result (among other things). This, along with another audit table that tracks individual table changes, provides all the logging we need per user.

You could also set up a connection pool in your application to control connections per application.

At first blush, I think trying to manage so many users is a burden that outweighs any possible benefits.


facilitate automated logging via triggers

You would definitely have a penalty to pay because you would introduce additional disk I/O using triggers to record every login. You could pull off some elaborate infrastructure nuances to alleviate most of that disk I/O as follows :

  • Logging users via triggers to BLACKHOLE tables
  • Set up replication slave to only accept SQL from the master's BLACKHOLE tables
  • Convert the BLACKHOLE table on the slave to MyISAM
  • Reading login statstics from the slave only
  • You have to live with additional disk I/O via binary logging

However, the introduction of triggers slows down app performance just to authenticate users, particularly if the number of user login is high. Rhetorical questions for your research:

  • Is the infrastructure suggestion and trigger coding able to handle a peak of user logins ?
  • Is the implementation of these ideas worth it if peaks are never seen ?
  • Is the implementation of these ideas worth it if you anticipate peaks in the future ?

control mysql connections on a per-(web-application-)user level

There is already a built-in feature of controlling mysql authentication in terms of the number of queries that can be done per hour. Please note them in the description of mysql.user in MySQL 5.5.12:

mysql> desc mysql.user;
+------------------------+-----------------------------------+------+-----+---------+-------+
| Field                  | Type                              | Null | Key | Default | Extra |
+------------------------+-----------------------------------+------+-----+---------+-------+
| Host                   | char(60)                          | NO   | PRI |         |       |
| User                   | char(16)                          | NO   | PRI |         |       |
| Password               | char(41)                          | NO   |     |         |       |
| Select_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Insert_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Update_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Delete_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Create_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Drop_priv              | enum('N','Y')                     | NO   |     | N       |       |
| Reload_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Shutdown_priv          | enum('N','Y')                     | NO   |     | N       |       |
| Process_priv           | enum('N','Y')                     | NO   |     | N       |       |
| File_priv              | enum('N','Y')                     | NO   |     | N       |       |
| Grant_priv             | enum('N','Y')                     | NO   |     | N       |       |
| References_priv        | enum('N','Y')                     | NO   |     | N       |       |
| Index_priv             | enum('N','Y')                     | NO   |     | N       |       |
| Alter_priv             | enum('N','Y')                     | NO   |     | N       |       |
| Show_db_priv           | enum('N','Y')                     | NO   |     | N       |       |
| Super_priv             | enum('N','Y')                     | NO   |     | N       |       |
| Create_tmp_table_priv  | enum('N','Y')                     | NO   |     | N       |       |
| Lock_tables_priv       | enum('N','Y')                     | NO   |     | N       |       |
| Execute_priv           | enum('N','Y')                     | NO   |     | N       |       |
| Repl_slave_priv        | enum('N','Y')                     | NO   |     | N       |       |
| Repl_client_priv       | enum('N','Y')                     | NO   |     | N       |       |
| Create_view_priv       | enum('N','Y')                     | NO   |     | N       |       |
| Show_view_priv         | enum('N','Y')                     | NO   |     | N       |       |
| Create_routine_priv    | enum('N','Y')                     | NO   |     | N       |       |
| Alter_routine_priv     | enum('N','Y')                     | NO   |     | N       |       |
| Create_user_priv       | enum('N','Y')                     | NO   |     | N       |       |
| Event_priv             | enum('N','Y')                     | NO   |     | N       |       |
| Trigger_priv           | enum('N','Y')                     | NO   |     | N       |       |
| Create_tablespace_priv | enum('N','Y')                     | NO   |     | N       |       |
| ssl_type               | enum('','ANY','X509','SPECIFIED') | NO   |     |         |       |
| ssl_cipher             | blob                              | NO   |     | NULL    |       |
| x509_issuer            | blob                              | NO   |     | NULL    |       |
| x509_subject           | blob                              | NO   |     | NULL    |       |
| max_questions          | int(11) unsigned                  | NO   |     | 0       |       |
| max_updates            | int(11) unsigned                  | NO   |     | 0       |       |
| max_connections        | int(11) unsigned                  | NO   |     | 0       |       |
| max_user_connections   | int(11) unsigned                  | NO   |     | 0       |       |
| plugin                 | char(64)                          | YES  |     |         |       |
| authentication_string  | text                              | YES  |     | NULL    |       |
+------------------------+-----------------------------------+------+-----+---------+-------+
42 rows in set (0.01 sec)

You have max_questions, max_updates, max_connections, and max_user_connections.

In MySQL 5.0, you can limit use of the following server resources for individual accounts:

  • max_questions : Number of queries that an account can issue per hour
  • max_updates - Number of updates that an account can issue per hour
  • max_connections : Number of times an account can connect to the server per hour
  • max_user_connections : Number of simultaneous connections to the server by an account

These can be managed for your app users by creating a corresponding mysql user for each app user. If you are planning to manage user limits, please remember not to reinvent the wheel since MySQL can control these aspects in its authentication protocol.

Tags:

Mysql