MariaDB 11.8.3へアップグレード後、rootユーザにunix_socketで接続できなくなる

こんばんは。tukapiyoです。

Debian 12(Bookworm)からDebian 13(Trixie)にアップグレードしたところ、MariaDB 10.11系から11.8.3へアップグレードされました。
正常に動作しているように見えたのですが、rootユーザでログインできなくなっていることに気づきました。

今回はこの事象を調査し、解消した記録です。

発生事象

mysqldumpの失敗

最初に気づいたのは、cronmysqldumpに失敗したエラーメールが届いたタイミングでした。
以下の様なメールが届きました。

mysqldump: Got error: 1698: "Access denied for user 'root'@'localhost'" when trying to connect

これはおかしいということで調査を始めました。

mysqlで接続できない

rootユーザからmysqlコマンドで接続しようとしても接続できません。
なお慣れているのでmysqlコマンドを実行していますが、mariadbコマンドを実行するのが今のやり方です。

$ sudo su -
# mysql -uroot
ERROR 1698 (28000): Access denied for user 'root'@'localhost'

なお、rootではないパスワード認証をしているユーザは問題なく接続できます。
そのせいもあってしばらく気づかなかったというのがあります。

調査

rootで認証

色々な方法でログインを試してみます。

# mysql -uroot --socket=/run/mysqld/mysqld.sock
ERROR 1698 (28000): Access denied for user 'root'@'localhost'
# mysql -uroot -p --socket=/run/mysqld/mysqld.sock
Enter password:
ERROR 1698 (28000): Access denied for user 'root'@'localhost'

# mysql -uroot --socket=/var/run/mysqld/mysqld.sock
ERROR 1698 (28000): Access denied for user 'root'@'localhost'

# mysql -uroot --protocol=TCP
WARNING: option --ssl-verify-server-cert is disabled, because of an insecure passwordless login.
ERROR 1698 (28000): Access denied for user 'root'@'localhost'

# mysql -uroot -p --protocol=TCP
Enter password:
ERROR 1698 (28000): Access denied for user 'root'@'localhost'

どれもだめですね。

journalctlでログ確認

mariadb.serviceのログを確認してみると以下の様に警告が出ていることが分かりました。
MariaDBをアップグレードしたからか(?)、mariadb-upgradeを実行しようとして失敗しているようです。

# journalctl -xeu mariadb
(..snip..)
/etc/mysql/debian-start[14886]: /usr/bin/mariadb-upgrade: the '--basedir' option is always ignored
/etc/mysql/debian-start[14886]: Reading datadir from the MariaDB server failed. Got the following error when executing the 'mysql' command line client
/etc/mysql/debian-start[14886]: ERROR 1698 (28000): Access denied for user 'root'@'localhost'
/etc/mysql/debian-start[14886]: FATAL ERROR: Upgrade failed
(..snip..)

mysqld-safeで強制ログインして確認

仕方ないので強制的にログインすることにします。
動作しているmariadb-serverを停止させてから、mysqld-safeコマンドに--skip-grant-tablesをつけて起動すれば認証をスキップできるようになります。
なお、mysqld-safeも同様に今風のコマンドはmariadbd-safeです。

# systemctl stop mariadb
# mysqld-safe --skip-grant-tables &
# mysqld -uroot
MariaDB [(none)]>

global_privの確認

ユーザの権限を確認します。
最近のMariaDBでは、mysqlデータベースのglobal_privテーブルに情報が保存されるようです。

MariaDB [(none)]> SELECT * FROM mysql.global_priv;

出力が長いので結果は省略しますが、権限がJSON形式で表示されます。
root@localhostの権限を抜粋すると、以下の様になっていました。

"plugin":"unix_socket","authentication_string":"*XXXXXXXXXXXXXXXXXXXXXXXXX"

authentication_stringはパスワードハッシュなので隠していますが値が入っています。

pluginsの確認

rootユーザはsocketでログインする設定になっていましたので、unix_socketプラグインが読み込まれているかどうか確認します。

MariaDB [(none)]> SHOW plugins;
+---------------------+----------+--------------------+--------------------+---------+
| Name                | Status   | Type               | Library            | License |
+---------------------+----------+--------------------+--------------------+---------+
  (..snip..)
| unix_socket         | ACTIVE   | AUTHENTICATION     | NULL               | GPL     |
  (..snip..)

unix_socketが表示されているので、どうやら読み込まれているようです。

試行錯誤

パスワード認証へ変更

一度パスワード認証へ変更してみます。
global_privテーブルの中をJSONを書き換えます。

MariaDB [(none)]> UPDATE mysql.global_priv SET priv = JSON_SET(priv, '$.plugin', 'mysql_native_password') WHERE User = 'root' AND Host = 'localhost';
Query OK, 1 row affected (0.001 sec)
Rows matched: 1 Changed: 1 Warnings: 0

MariaDB [(none)]> \q
Bye

書き換えたら、バックグラウンドで動作させているmysqld_safeを終了しMariaDBを通常起動させます。

# jobs
[1]+ Running mysqld_safe --skip-grant-tables &
# kill %1
# jobs
[1]+ Done mysqld_safe --skip-grant-tables
# systemctl start mariadb

この状態でログインを試してみます。

# mysql -uroot
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
# mysql -uroot -p
Enter password:

MariaDB [(none)]> \q
Bye

パスワード認証で入ることができましたね。
でもこれでは解決していません。

ちなみにjournalctlでログを見てみますとメッセージが変わっています。

# journalctl -xeu mariadb
(..snip..)
/etc/mysql/debian-start[20979]: /usr/bin/mariadb-upgrade: the '--basedir' option is always ignored
/etc/mysql/debian-start[20979]: Reading datadir from the MariaDB server failed. Got the following error when executing the 'mysql' command line client
/etc/mysql/debian-start[20979]: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
/etc/mysql/debian-start[20979]: FATAL ERROR: Upgrade failed
(..snip..)

以前はERROR 1698でしたが、ERROR 1045でパスワードが未指定なのでアクセスできないというメッセージに変わりました。
パスワード認証になったので当然ですね。

mariadb-upgrade

無事にrootでログインできるようになったことですし、データベースのアップグレードをしたら変わるかもしれません。
手動でmariadb-upgradeを実行してみましょう。

# mariadb-upgrade -p
Enter password:
Phase 1/8: Checking and upgrading mysql database
Processing databases
mysql
mysql.column_stats OK
(..snip..)
Phase 7/8: uninstalling plugins
Phase 8/8: Running 'FLUSH PRIVILEGES'
OK

データベースのアップグレードは無事に完了しました。

ソケット認証に変更(UPDATE)

それではソケット認証にもう一度戻して状況を確認してみましょう。
変更後mariadb.serviceを再起動します。

# mysql -uroot -p
Enter password:

MariaDB [(none)]> UPDATE mysql.global_priv SET priv = JSON_SET(priv, '$.plugin', 'unix_socket') WHERE User = 'root' AND Host = 'localhost';
Query OK, 1 row affected (0.001 sec)
Rows matched: 1 Changed: 1 Warnings: 0

MariaDB [(none)]> \q
Bye
# systemctl stop mariadb
# systemctl start mariadb

状況を確認してみましょう。

# mysql -uroot
ERROR 1698 (28000): Access denied for user 'root'@'localhost'
# mysql -uroot -p
Enter password:
ERROR 1698 (28000): Access denied for user 'root'@'localhost'
# journalctl -xeu mariadb
(..snip..)
/etc/mysql/debian-start[21117]: /usr/bin/mariadb-upgrade: the '--basedir' option is always ignored
/etc/mysql/debian-start[21117]: Reading datadir from the MariaDB server failed. Got the following error when executing the 'mysql' command line client
/etc/mysql/debian-start[21117]: ERROR 1698 (28000): Access denied for user 'root'@'localhost'
/etc/mysql/debian-start[21117]: FATAL ERROR: Upgrade failed
(..snip..)

見ての通り何も解決していません。
mariadb-upgradeを手動で実行しても解決しませんでしたし、そもそもmariadb-upgradeはサービス起動時に毎回実行しているようです。

解決

ソケット認証に変更2回目(ALTER)

MariaDBの認証周りの仕様を確認しようと思い、公式ドキュメントを漁ってみました。

すると、認証方式の変更方法が間違っていることに気づきます。
UPDATEではなく、ALTER使えとのこと。

試してみましょう。
現在はまたrootにログインできない状況ですので、まずはmysqld_safeで再起動をしてパスワード認証へ変更後、改めてサービスを起動します。
ここではまだUPDATEで変更します(パスワード認証への変更はUPDATEでも問題なかったため)。

# mysqld_safe --skip-grant-tables &
# mysql -uroot

MariaDB [(none)]> UPDATE mysql.global_priv SET priv = JSON_SET(priv, '$.plugin', 'mysql_native_password') WHERE User = 'root' AND Host = 'localhost';
Query OK, 1 row affected (0.001 sec)
Rows matched: 1 Changed: 1 Warnings: 0

MariaDB [(none)]> \q
Bye
# jobs
[1]+ Running mysqld_safe --skip-grant-tables &
# kill %1
# jobs
[1]+ Done mysqld_safe --skip-grant-tables
# systemctl start mariadb

ALTERで認証方式を変更します。
ALTER前後のglobal_privも見たくなったので見ておきます。

# mysql -uroot -p
Enter password:

MariaDB [(none)]> SELECT * FROM mysql.global_priv;
(..snip..)
"plugin":"mysql_native_password","authentication_string":"*XXXXXXXXXXXXXXXXXXXXXXXXX"
(..snip..)

MariaDB [(none)]> ALTER USER root@localhost IDENTIFIED VIA unix_socket;
Query OK, 0 rows affected (0.001 sec)

MariaDB [(none)]> select * from mysql.global_priv;
(..snip..)
"plugin":"unix_socket","authentication_string":""
(..snip..)

MariaDB [(none)]> \q
Bye

なんと、authentication_stringが空欄になりました。
unix_socket認証だとパスワード不要なので当然と言えば当然ですが、何となく原因がこれな気がしてきます。

認証

再度ログインを試してみましょう。

# mysql -uroot

MariaDB [(none)]> \q
Bye

ログインできましたね…
念のためmariadb.serviceを再起動してから試してみましょう。

# systemctl stop mariadb
# systemctl start mariadb
# mysql -uroot

MariaDB [(none)]> \q
Bye

ログインできました!

journalctlでログ確認

mariadb.service再起動後のログも見てみます。

# journalctl -xeu mariadb
(..snip..)
/etc/mysql/debian-start[21776]: /usr/bin/mariadb-upgrade: the '--basedir' option is always ignored
(..snip..)

mariadbd-upgradeの認証失敗エラーが消えています!

原因

どうやら、unix_socketで認証する設定のとき、authentication_string(つまりはパスワード)が設定されているとログインできなくなるようです。
もう少し確認を進めてみます。

パスワードの設定

unix_socketにパスワードを設定してみます…と、パスワードを設定するのは許されないようです。

# mysql -uroot

MariaDB [(none)]> SET PASSWORD = PASSWORD('hogehogefugafuga');
ERROR 1699 (HY000): SET PASSWORD is not applicable for users authenticating via unix_socket plugin
MariaDB [(none)]> \q
Bye

ちなみに、UPDATEauthentication_stringを設定すると普通に設定できるのですが、その後ログインできなくなるかと言えば、できてしまいました。
あえてログは載せませんが。

結論

  • 何らかの不整合が発生していたと思われる
  • ログインできなくなったら、mysqld_safe --skip-grant-tables
  • unix_socket利用時はパスワードを設定しない
  • ALTERコマンドで認証方式を設定する(と直る?)

おすすめ

コメントを残す

Amazon プライム対象