MySQLのrootユーザを削除したときの対処

ぼーっと作業して何故か消してしまったときの対処法。例はCentOSです。パスなどは適時読み替えてください。
まずMySQLを停止します。

# /etc/init.d/mysql stop

MySQLを認証無視モードで起動します。--skip-grant-tablesが無視フラグです。

# /usr/sbin/mysqld --basedir=/ --datadir=/var/lib/mysql --user=mysql --pid-filk --skip-grant-tables &

これでmysqlにrootでログインできます。

# mysql -u root

このモードだとgrantが無効なので、普通の手法ではrootを復帰できなようです。
とりあえず、どのテーブルでも覗けるのでmysql.userを見てみます。

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       |       |
| 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       |       |
+-----------------------+-----------------------------------+------+-----+---------+-------+
37 rows in set (0.00 sec)

次にrootが残っている正常なホストのDBから設定を取得してみます。適当に整形すると以下のようなデータです。

Host                  	localhost
User                  	root
Password              	パスワードのハッシュ
Select_priv           	Y
Insert_priv           	Y
Update_priv           	Y
Delete_priv           	Y
Create_priv           	Y
Drop_priv             	Y
Reload_priv           	Y
Shutdown_priv         	Y
Process_priv          	Y
File_priv             	Y
Grant_priv            	Y
References_priv       	Y
Index_priv            	Y
Alter_priv            	Y
Show_db_priv          	Y
Super_priv            	Y
Create_tmp_table_priv 	Y
Lock_tables_priv      	Y
Execute_priv          	Y
Repl_slave_priv       	Y
Repl_client_priv      	Y
Create_view_priv      	Y
Show_view_priv        	Y
Create_routine_priv   	Y
Alter_routine_priv    	Y
Create_user_priv      	Y
ssl_type              	
ssl_cipher            	
x509_issuer           	
x509_subject          	
max_questions         	0
max_updates           	0
max_connections       	0
max_user_connections  	0

フラグ全部立てで良さそうです。
設定を参考にrootを作り直してみます。

mysql> use mysql;
mysql> insert into user (user, host, password) values('root', 'localhost', PASSWORD('pass'));
mysql> update user set
    -> Select_priv='Y',
    -> Insert_priv='Y',
    -> Update_priv='Y',
    -> Delete_priv='Y',
    -> Create_priv='Y',
    -> Drop_priv='Y',
    -> Reload_priv='Y',
    -> Shutdown_priv='Y',
    -> Process_priv='Y',
    -> File_priv='Y',
    -> Grant_priv='Y',
    -> References_priv='Y',
    -> Index_priv='Y',
    -> Alter_priv='Y',
    -> Show_db_priv='Y',
    -> Super_priv='Y',
    -> Create_tmp_table_priv='Y',
    -> Lock_tables_priv='Y',
    -> Execute_priv='Y',
    -> Repl_slave_priv='Y',
    -> Repl_client_priv='Y',
    -> Create_view_priv='Y',
    -> Show_view_priv='Y',
    -> Create_routine_priv='Y',
    -> Alter_routine_priv='Y',
    -> Create_user_priv='Y'
    -> where User='root';
mysql> exit

ps aux などでプロセスを探してMySQLをkill -KILLしてください。
で、普通に起動し直します。

# /etc/init.d/mysql start

以上でrootが戻ります。

参考 blog.katsuma.tv