问题产生

今天用命令行登陆 mysql 时出现了 Error。

1
2
mysql -uroot -p
ERROR 16958 (28000): Access denied for user 'root'@'localhost'

起初我以为是 root 密码错了,于是就去 mysql 官方文档查了下改密码的方法

关闭 mysql 进程然后再建立一个改密码的 sql 文件

1
2
3
4
$ systemctl stop mysql.service

$ cd /tmp && vim init.sql #xxxxxx 代表要修改的密码
alter user 'root'@'localhost' identified by 'xxxxxx';

安全模式启动 mysql

1
$ mysqld_safe --defaults-file=/etc/mysql/my.cnf --init-file=/tmp/init.sql &

然后重启 mysql

1
$ systemctl restart mysql.service

这样把密码改为了 xxxxxx

然后我再去登陆

1
2
mysql -uroot -p
ERROR 16958 (28000): Access denied for user 'root'@'localhost'

=͟͟͞͞(꒪⌓꒪*)

并不是密码错误的锅

问题关键

求助了强大的 google 和 stackoverflow,终于找到了问题。

The reason is that recent Ubuntu installation (maybe others also), mysql is using by default the UNIX auth_socket plugin.

Basically means that: db_users using it, will be “auth” by *the system user credentias.

user 表中的用户的 plugin 默认会设置为 auth_socket,这样的话,认证会由系统用户证书来进行。

1
2
3
4
5
6
7
8
9
10
11
12
$ sudo mysql -u root # I had to use "sudo" since is new installation

mysql> USE mysql;
mysql> SELECT User, Host, plugin FROM mysql.user;

+------------------+-----------------------+
| User | plugin |
+------------------+-----------------------+
| root | auth_socket |
| mysql.sys | mysql_native_password |
| debian-sys-maint | mysql_native_password |
+------------------+-----------------------+

解决方案

有两种解决方案,但都需要登陆进 mysql,所以需要重启 mysql 开启 --skip-grant-tables 参数,来跳过权限表的加载

1
2
3
4
5
$ systemctl stop mysql.service
$ mysqld_safe --defaults-file=/etc/mysql/my.cnf --skip-grant-tables --skip-networking &
$ sudo mysql # 这样就可以免登录直接进入 mysql 交互界面

mysql>

方法 1

把 mysql 的 root 用户的 plugin 字段设置为 mysql_native_password

1
2
3
4
5
6
mysql> USE mysql;
mysql> UPDATE user SET plugin='mysql_native_password' WHERE User='root';
mysql> FLUSH PRIVILEGES;
mysql> exit;

$ systemctl restart mysql.service

方法 2

新建一个 root 用户

1
2
3
4
5
6
7
8
9
mysql> USE mysql;
mysql> CREATE USER 'YOUR_SYSTEM_USER'@'localhost' IDENTIFIED BY 'xxxxxx';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root2'@'localhost';
mysql> UPDATE user SET plugin='auth_socket' WHERE User='root2';
mysql> FLUSH PRIVILEGES;
mysql> exit;

$ service mysql restart
$ mysql -u root2 -pxxxxxx # 用 root2 来登陆