そんなときのTIPS。
まず、ダミーのデータディレクトリをmysql_install_dbで作ります。これはrpmで入れた環境なので、/usrはbasedirです。
$ cd /usr $ bin/mysql_install_db --no-defaults --datadir=/home/mysql/dummy
ここに、パスワードを変えたいMySQLのmysql.userテーブルをコピーします。少なくともMySQL 5.7.8現在、mysql.userはまだMyISAMなのでコピーできます。
rootが使えないはずなのにmysql.userテーブルがゴリゴリ更新されているような環境があるはずはないと信じているので、取り敢えずはシンプルなcpで大丈夫です。
コピーしたらダミーのデータディレクトリを使ってMySQLを起動します。--socketオプションを忘れると本番のソケットファイルが握りつぶされる可能性があるので注意。。
$ cp -ip /var/lib/mysql/mysql/user.MYD /home/mysql/dummy/mysql/user2.MYD $ cp -ip /var/lib/mysql/mysql/user.MYI /home/mysql/dummy/mysql/user2.MYI $ cp -ip /var/lib/mysql/mysql/user.frm /home/mysql/dummy/mysql/user2.frm $ bin/mysqld_safe --no-defaults --datadir=/home/mysql/dummy --port=23000 --socket=/home/mysql/dummy/mysql.sock & $ bin/mysql -uroot -S/home/mysql/dummy/mysql.sock mysql> SELECT user, host, password FROM mysql.user2; +-------------+-----------------+-------------------------------------------+ | user | host | password | +-------------+-----------------+-------------------------------------------+ | root | localhost | *........................................ | | xxxxxxxxx | localhost | *........................................ | | root | 127.0.0.1 | *........................................ | | xxxxxxxx | xxx.xxx.xxx.% | *........................................ | | xxxxxxxxxxx | localhost | *........................................ | | xxxx | localhost | *........................................ | | xxxxx | xxx.xxx.xxx.% | *........................................ | | xxxxx | xxx.xxx.xxx.xxx | *........................................ | +-------------+-----------------+-------------------------------------------+ 8 rows in set (0.00 sec)
この通りコピーできたので、UPDATEステートメントでパスワードを書き換えます。
mysql> UPDATE mysql.user2 SET password= PASSWORD('Do_you_love_Perl6?') WHERE (user, host)= ('root', 'localhost');
更新できたらダミー側のMySQLを落とし、落とせない方のMySQLのmysql.userテーブルを上書きします(といってもバックアップは取っておいた方が良かろうかと)
$ bin/mysqladmin -uroot -S/home/mysql/dummy/mysql.sock shutdown $ cp -ip /home/mysql/dummy/mysql/user2.MYD /var/lib/mysql/mysql/user.MYD $ cp -ip /home/mysql/dummy/mysql/user2.MYI /var/lib/mysql/mysql/user.MYI
さてこの状態だと、「mysql.userテーブルにUPDATEはかかっているけどFLUSH PRIVILEGESが必要な状態」であり、「でもFLUSH PRIVILEGESするためのrootに接続できない」状態になるかと思います。
そこでkill -HUPですよ奥さん。
$ pkill -HUP mysqld $ pkill -HUP mysqld
SIGHUPを受け取ると このへんのコード を通って、"FLUSH PRIVILEGES"や"FLUSH HOSTS", "FLUSH LOGS"その他と同じ処理が流れるので、MySQL上のアカウントにアクセスできなくても無事"FLUSH PRIVILEGES"できる。
…コード上通ってそうなのに、何故か2回SIGHUP送らないと反映されない(5.1でも5.6でも5.7でも…なんだろう。同じif文の中のmysql_print_statusはちゃんと呼ばれてエラーログにデバッグ情報吐いてるのに。。)ので取り敢えず2回やっている。深く考えてはいない。
この手段を一番よく使うのはアレですね。
ソケットファイルが何故か消えてて、--skip-name-resolveでroot@localhostはあるけどroot@127.0.0.1がないから--protocol=tcpで逃げられない時に、root@127.0.0.1を作るのに使います。。
【2015/10/16 15:43】
たぶん、内部的にprivilegeを読みなおしてからflush tablesしてる(この段階で古いファイルが閉じられる)から… > 「何故か2回SIGHUP送らないと反映されない」 / “日々の覚書: MySQLのrootのパスワ…” http://t.co/lljTEsYJFm
— Kazuho Oku (@kazuho) 2015, 10月 16
その通りでした! ありがとうございます!!
https://github.com/mysql/mysql-server/blob/5.6/sql/sql_reload.cc#L56-L69
0 件のコメント :
コメントを投稿