求助:Python自动化安装MySQL 8时,root临时密码无法通过脚本重置的替代方案
我正在写Python脚本自动化部署MySQL 8,目前已经搞定了创建mysql用户、下载解压安装RPM包这些步骤。但安装完成后,想用MySQL Connector通过临时密码登录root用户修改密码时,碰到了密码过期错误——脚本里连不上数据库,提示必须用支持过期密码的客户端登录修改。
当前尝试的代码片段
def login_to_mysql_db_inst(username, password): mydb = mysql.connector.connect( host="localhost", user=username, password=password ) print(mydb) return mydb if __name__ == "__main__": create_mysql_user(target_user) # 创建mysql用户 download_mysql(db_version) # 下载解压MySQL文件 make_dirs_fn() # 创建数据和日志目录 chown_dirs_fn() # 给mysql用户设置目录权限 resolve_dependencies() # 移除冲突文件 install() # 安装MySQL write_config_to_file(cfengine_hostclass_lines, '/etc/cfengine-hostclasses.txt') write_config_to_file(mysql_config_lines, '/etc/my.cnf') run_cmd(["service","mysqld","start"]) # 启动服务 run_cmd(["service","mysqld","status"]) # 检查状态 run_cmd(["chkconfig", "mysqld", "on"]) # 设置开机自启 temp_password = get_temporary_mysql_password() mydb = login_to_mysql_db_inst('root',temp_password) curr = mydb.cursor() curr.execute("ALTER USER 'root'@'localhost' IDENTIFIED BY '*************';")
遇到的错误信息
Traceback (most recent call last): File "/usr/local/lib64/python3.6/site-packages/mysql/connector/connection_cext.py", line 236, in _open_connection self._cmysql.connect(**cnx_kwargs) _mysql_connector.MySQLInterfaceError: Your password has expired. To log in you must change it using a client that supports expired passwords. During handling of the above exception, another exception occurred: Traceback (most recent call last): File "mysql_install_script.py", line 283, in <module> login_to_mysql_db_inst('root',temp_password) File "mysql_install_script.py", line 250, in login_to_mysql_db_inst password=password File "/usr/local/lib64/python3.6/site-packages/mysql/connector/__init__.py", line 272, in connect return CMySQLConnection(*args, **kwargs) File "/usr/local/lib64/python3.6/site-packages/mysql/connector/connection_cext.py", line 85, in __init__ self.connect(**kwargs) File "/usr/local/lib64/python3.6/site-packages/mysql/connector/abstracts.py", line 1028, in connect self._open_connection() File "/usr/local/lib64/python3.6/site-packages/mysql/connector/connection_cext.py", line 242, in _open_connection sqlstate=exc.sqlstate) mysql.connector.errors.DatabaseError: 1862 (HY000): Your password has expired. To log in you must change it using a client that supports expired passwords.
手动用终端执行mysql -u root -p {temp_password}再运行ALTER USER命令是可以成功的,但想通过脚本自动化完成,求可行的解决思路?
推荐的几种解决方案
方案1:通过subprocess调用MySQL命令行工具(最稳妥)
MySQL自带的命令行客户端支持--connect-expired-password参数,允许用过期密码登录并执行密码修改操作。我们可以用Python的subprocess模块直接调用这个命令,绕开Connector的限制:
import subprocess temp_password = get_temporary_mysql_password() new_root_password = "你的安全新密码" # 方式1:用列表形式构造命令(更安全,避免shell注入风险) cmd = [ "mysql", "-u", "root", f"-p{temp_password}", "--connect-expired-password", "-e", f"ALTER USER 'root'@'localhost' IDENTIFIED BY '{new_root_password}';" ] # 执行命令,check=True会在命令失败时抛出异常 subprocess.run(cmd, check=True) # 方式2:如果需要处理特殊字符,也可以用管道传递SQL(注意shell=True的风险) # sql_cmd = f"ALTER USER 'root'@'localhost' IDENTIFIED BY '{new_root_password}';" # subprocess.run(f"echo '{sql_cmd}' | mysql -u root -p'{temp_password}' --connect-expired-password", shell=True, check=True)
这个方法的优势是兼容性强,不管Python Connector版本如何,只要MySQL命令行工具存在就能用,和你手动操作的逻辑完全一致。
方案2:修改MySQL Connector的连接参数
如果不想调用外部命令,可以试试给connect()方法添加connect_expired_password=True参数,部分版本的MySQL Connector支持这个参数来处理过期密码的登录:
def login_to_mysql_db_inst(username, password): mydb = mysql.connector.connect( host="localhost", user=username, password=password, connect_expired_password=True # 添加这个参数 ) print(mydb) return mydb # 之后再执行ALTER USER命令即可
不过要注意,这个参数在较老版本的Connector中可能不存在,比如你用的Python 3.6搭配的Connector可能不支持,所以方案1更可靠。
方案3:安装时跳过临时密码生成
如果你的自动化环境允许,可以在初始化MySQL的时候用--initialize-insecure参数,这样不会生成临时密码,root用户直接无密码登录,之后再设置密码。不过这个方法要考虑环境安全性,适合内部可信环境使用。
备注:内容来源于stack exchange,提问作者madrarua

