前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[MYSQL] mysql忘记密码怎么办?

[MYSQL] mysql忘记密码怎么办?

原创
作者头像
大大刺猬
发布2024-09-19 18:06:14
2480
发布2024-09-19 18:06:14
举报
文章被收录于专栏:大大刺猬

导读

天有不测风云, 今晚(20240919,上海)台风Pulasan就要来了. 难免有忘记mysql密码的时候. 解决办法网上也是一找一大堆的. 这里做个小小的介绍. (不考虑history里面能查询到的情况, 况且那也不属于忘记密码的范畴)

忘记密码的处理方法

ALTER修改(0星)

如果是忘记普通账号的密码, 可以在业务端配置文件找(能找到的话, 估计也看不到这了.). 更多的情况是都找不到了. 只能重置密码. 命令参考

代码语言:sql
复制
alter user username@'%' identified with mysql_native_password by '123456';
flush privileges;

注: 最新版mysql不在支持mysql_native_password插件了.

skip_grant_tables(1星)

多数情况, 我们都是忘记root的密码了. 不然都可以使用第一种方法来解决. mysql也预料到了这种情况. 于是整了个参数skip_grant_tables , 该参数为True时,即不做权限/密码认证, 任何账号都能直接登录, 这很危险, 于是又整了个参数skip_networking 来限制TCP/IP连接, 这样我们修改密码的时候,还可以通过socket来连接, 但是其它账号就不能通过网络连接了. 算是安全了.(如果其它人都能登录OS了的话, 也是可以通过socket连接的, 但这属于OS那边的'锅')

--skip-grant-tables

| Command-Line Format | --skip-grant-tables[={OFF|ON}] |

| ------------------- | -------------------------------- |

| Type | Boolean |

| Default Value | OFF |

skip_networking

| Command-Line Format | --skip-networking[={OFF|ON}] |

| ---------------------------------------- | ------------------------------ |

| System Variable | skip_networking |

| Scope | Global |

| Dynamic | No |

| SET_VAR Hint Applies | No |

| Type | Boolean |

| Default Value | OFF |

这两参数都需要重启数据库. 修改方法可参考如下:

代码语言:shell
复制
# 停库
systemctl stop mysqld
# 编辑配置文件, 增加那两参数
vim my.cnf
skip_grant_tables
skip_networking # 可选
# 启库
systemctl start mysqld
# 登录数据库,并修改密码
mysql -S /tmp/mysql.sock
flush privileges;
alter user root@'localhost' identified with mysql_native_password by '123456';
flush privileges;
# 再把参数修改回去
vim my.cnf
# 再重启
systemctl restart mysqld
# 使用新密码登录数据库确认
mysql -S /tmp/mysql.sock -p123456

init_file(2星)

第二种方法有丢丢麻烦, 于是官方还有个参数init_file 也能实现修改密码. 该参数表示数据库启动的时候执行的SQL语句, 是不需要验证权限的. 所以我们可以让它直接我们的修改密码的语句就能达到修改密码的要求.

init_file

Command-Line Format

--init-file=file_name

System Variable

init_file

Scope

Global

Dynamic

No

SET_VAR Hint Applies

No

Type

File name

官方重置root密码的教程也是使用的这个参数.

代码语言:shell
复制
# 编辑sql文件
vim conf/init.sql
alter user root@'localhost' identified with mysql_native_password by '123456';

# 编辑配置文件
vim conf/my.cnf
init_file='xxx/conf/init.sql'

# 重启数据库
systemctl restart mysqld

# 验证密码
mysql -S /tmp/mysql.sock -p123456

# 把参数文件修改回去(可选), 不改的话, 每次重启密码都被重置为这个密码了.

这个方法相对于上面的的skip_grant_tables要简单很多, 但也要重启.

爆破

前面几种都是比较常见的方法, 除了第一种都要重启. 生产环境重启不是一件容易的事. 那么有没有不需要重启的方法呢? 当然有了, 那就是爆破(不是团队竞技). 如果每次都建立tcp连接的话, 效率是非常低的, 而且还可能影响业务的正常使用. 我们知道mysql_native_password的加密方法是做2次hash, 也就是我们可以比较hash之后的值是否一致来判断密码是否正确. mysql.user表 保存的也是加密之后的密码, 所以我们可以查看该表来获取加密后的密码, 但现在不是登录不了数据库么, 怎么查看呢?

诶, 我们昨天刚解析了mysql.ibd文件, 里面就有mysql.user表的数据啊. 使用方法如下: (我这里加了个if,只解析mysql表的数据)

代码语言:shell
复制
python3 get_mysql_ibd.py /data/mysql_dev/data/mysql.ibd

简单点的方法,我们可以拿该密码去一些hash网站查询.(但可能有的会收费, 但也有免费的)

如果密码很复杂的话, 可能在线查询不到. 而且在线查询还不安全, 这里就可以自己来爆破了. python版爆破方法参考:

代码语言:python
代码运行次数:0
复制
import binascii
import hashlib

NEW_PASSWORD = '1234567'
# 这里是二进制的. 需要的话, 可以转为str
PASSWORD = b'*'+binascii.hexlify(hashlib.sha1(hashlib.sha1(NEW_PASSWORD.encode()).digest()).digest())

mysql_config_editor.sh (3星)

有种特殊情况是, 忘记了mysql的密码, 但是之前配置了免登(mysql_config_editor),还可以登录数据库, 那么就可以直接修改密码(同时重新配置免登文件). 还有种更优雅的方法, 就是解析~/.mylogin.cnf文件内容. 好巧不巧我们之前就写过这种方法, 这里就不再介绍了, 感兴趣的自己看: https://www.modb.pro/db/1765168815701299200 相关的脚本可以直接在墨天轮下载

这种场景虽然少, 但今天恰好就用到了(文章写得断断续续的原因.....). 从库配置了免密, 但主库没有配. 这时候就可以去从库解析,然后在主库上面配置了.

修改mysql.ibd文件 (4星)

前面那些都还算普通操作, 这里开始我们就要来点骚操作了.

既然我们已经能解析ibd文件了, 那么我们就能修改mysql.ibd文件里面root的密码信息, 改为我们要的密码不就行了么.

首先我们得找到密码的位置(PAGENO和OFFSET), 欸, 我们的ibd2sql就有这个功能(--debug).

mysql.user是host,user作为主键的, localhost是字母通常在%后面, 所以基本上都是最后一条, 很快就能找到的.

代码语言:shell
复制
# 编辑脚本, 打开debug功能
vim  get_mysql_ibd.py 
ddcw.DEBUG = True

# 解析解析
python3 get_mysql_ibd.py /data/mysql_dev/data/mysql.ibd

这里我们就得到了 root@localhost的PAGENO=757, 往后面走, 找到密码位置.

于是我们得到了OFFSET=2513

然后我们适用如下脚本修改密码并生成一个新的mysql.ibd文件(最近修改ibd文件的脚本基本上都差不多, 注意crc32校验别忘了哟)

代码语言:python
代码运行次数:0
复制
#!/usr/bin/env python3
# write by ddcw @https://github.com/ddcw/ibd2sql
# 修改Mysql密码的脚本
import binascii
import hashlib
import struct,os,sys


PAGENO = 757
OFFSET = 2513
filename = '/data/mysql_dev/data/mysql.ibd'
filename2 = '/tmp/mysql.ibd'
NEW_PASSWORD = '123456'

PAGE_SIZE = 16384
NEW_PASSWORD = b'*'+binascii.hexlify(hashlib.sha1(hashlib.sha1(NEW_PASSWORD.encode()).digest()).digest())
def create_crc32c_table():
	poly = 0x82f63b78
	table = []
	for i in range(256):
		crc = i
		for _ in range(8):
			if crc & 1:
				crc = (crc >> 1) ^ poly
			else:
				crc >>= 1
		table.append(crc)
	return table

crc32_slice_table = create_crc32c_table()
def calculate_crc32c(data):
	crc = 0xFFFFFFFF
	for byte in bytearray(data): # for PY2
		crc = crc32_slice_table[(crc ^ byte) & 0xFF] ^ (crc >> 8)
	return crc ^ 0xFFFFFFFF

def replace_crc32(data):
	c1 = calculate_crc32c(data[4:26])
	c2 = calculate_crc32c(data[38:PAGE_SIZE-8])
	cb = struct.pack('>L',(c1^c2)&(2**32-1))
	data = cb + data[4:PAGE_SIZE-8] + cb + data[PAGE_SIZE-4:]
	return data


f2 = open(filename2,'wb')
with open(filename,'rb') as f:
	current_pageno = -1
	while True:
		data = f.read(PAGE_SIZE)
		if data == b'':
			break
		current_pageno += 1
		if current_pageno == PAGENO:
			data = data[:OFFSET] + NEW_PASSWORD + data[OFFSET+len(NEW_PASSWORD):]
			data = replace_crc32(data)
		f2.write(data)

f2.close()

直接执行该脚本, 然后替换掉系统的mysql.ibd文件(建议先备份)

代码语言:shell
复制
python3 modify_password.py
cp -ra /data/mysql_dev/data/mysql.ibd /data/mysql_dev/data/mysql.ibd.bak20240919
chown mysql:mysql /tmp/mysql.ibd 
mv /tmp/mysql.ibd /data/mysql_dev/data/mysql.ibd

欸, 这就好了么. 我们先解析这个文件验证下呢(把debug关了, 不然信息太多,看起来乱七八糟的,到处都是 by Neeko)

mysqld.ibd文件内容确实是我们修改之后的密码了. 那么我们登录数据库试下呢

居然不行

flush privileges和flush tables也试了均不行.

那我们重启试下吧.

重启之后确实可以. 但还是要重启, 而且步骤感觉也不少. 还不如init_file那个

修改内存

以前在某平台学习了一个适用c++修改cs1.6金币的方法, 就是直接修改内存(数字比较多,多修改几次,看看变化的是哪些, 修改那部分的值即可). 那理论上也可以修改mysqld进程的内存数据,把密码修改为我们实际的那个. 看了下内存dump文件, 可能存在多个密码相同的账号, 修改的难度较大. (能力有限, 就不卖弄了)

gdb跳过认证

使用gdb接管mysqld进程, 待到连接过来的时候, 直接放行即可. 这操作更骚, 且难度不小. 未验证过此方法的可行性.

总结

通常建议前3种方法, 后面几种不太推荐

方法

难度

优点

缺点/限制

ALTER

0星

简单,不需要重启

只能修改普通账号的密码, 需要高权限的账号登录, 业务得同步相关信息

skip_grant_tables

1星

简单?

过程比较啰嗦, 需要多次重启数据库

init_file

2星

简单,官方提供的方法

需要重启

爆破

3星

不需要重启

成本高, 不优雅

mysql_config_editor.sh

3星

简单

适用场景太TM有限了

修改mysql.ibd文件

4星

还是TM要重启

修改内存

5星

不需要重启

危险

gdb跳过认证

离谱

不需要重启

离了个大谱

参考:

https://dev.mysql.com/doc/refman/8.0/en/server-options.html#option_mysqld_skip-grant-tables

https://dev.mysql.com/doc/refman/8.0/en/resetting-permissions.html

https://github.com/ddcw

题外话

甲方要求工时饱和度, 所以后面加班会多点(DBA加班能干啥? dba事情越少越好啊, dba事情多的话就有大问题咯. 但作为外包,只能:好的), 写文章的时间好像还多了???

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导读
  • 忘记密码的处理方法
    • ALTER修改(0星)
      • skip_grant_tables(1星)
        • init_file(2星)
          • 爆破
            • mysql_config_editor.sh (3星)
              • 修改mysql.ibd文件 (4星)
                • 修改内存
                  • gdb跳过认证
                  • 总结
                  相关产品与服务
                  云数据库 MySQL
                  腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档