Docker容器中用entrypoint.sh修改MariaDB密码遇1045权限错误
问题:Docker容器中MariaDB root密码修改失败,报错1045
现象
在Docker容器的entrypoint.sh中编写修改MariaDB root密码的代码:
service mariadb start # set db root password mysql --user='root' --password='root' -e "\ GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY 'test'; FLUSH PRIVILEGES; \ GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'test'; FLUSH PRIVILEGES;"
无论使用哪种密码格式(如--passwordroot、-proot、-p"root"等),都会抛出错误:
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
Dockerfile关键部分:
FROM ubuntu:22.10 ENV DB_ROOT_PW=root COPY src/* /tmp/ RUN apt-get update && \ apt-get install -y \ cron # db, webserver RUN apt-get install -y \ mariadb-server \ mysqltuner \ apache2 RUN service mariadb start && \ mysql -h localhost -u root -e "\ GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY 'root'; FLUSH PRIVILEGES; \ GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root'; FLUSH PRIVILEGES;" RUN cp /tmp/docker_entry.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/docker_entry.sh ENTRYPOINT [ "docker_entry.sh" ]
手动进入容器执行命令正常,但脚本执行失败。更新后发现:
- 把
entrypoint.sh简化为仅service mariadb start,仍报错1045; - 构建镜像时不设置root密码则无报错,但手动设密码后,重启容器必现该错误。
原因分析
- MariaDB启动异步性:
service mariadb start是异步启动,脚本执行mysql命令时,数据库可能还未完成初始化,此时root用户的密码验证逻辑未就绪,导致报错。 - 镜像与容器状态差异:
RUN阶段设置密码后,镜像保存的是静态文件系统,但容器启动时MariaDB会重新读取配置,若无正确初始化逻辑,会出现密码不匹配或验证异常。 - 错误提示误导性:报错
using password: NO是因为数据库未完全启动时,即使传入密码,服务端也未处理验证,导致客户端误判为未传密码。
解决方案
方案1:等待MariaDB完全就绪后执行操作
修改entrypoint.sh,增加等待逻辑确保数据库启动完成:
#!/bin/bash # 启动MariaDB service mariadb start # 最多等待30秒,直到数据库就绪 MAX_WAIT=30 WAIT_COUNT=0 until mysqladmin ping -h localhost --silent; do sleep 1 WAIT_COUNT=$((WAIT_COUNT+1)) if [ $WAIT_COUNT -ge $MAX_WAIT ]; then echo "MariaDB启动超时" exit 1 fi done # 修改root密码(初始无密码时无需--password参数) mysql -u root -e "\ GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY 'test'; FLUSH PRIVILEGES; \ GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'test'; FLUSH PRIVILEGES;" # 保持容器运行 tail -f /var/log/mariadb/mariadb.log
方案2:利用MariaDB初始化脚本机制
MariaDB首次启动时会执行/docker-entrypoint-initdb.d/目录下的脚本,通过这个机制配置密码更可靠:
- 修改Dockerfile,移除
RUN阶段的密码设置,添加初始化脚本复制:
FROM ubuntu:22.10 ENV DB_ROOT_PW=test COPY src/* /tmp/ COPY src/init_db.sql /docker-entrypoint-initdb.d/ RUN apt-get update && \ apt-get install -y cron mariadb-server mysqltuner apache2 # 允许远程连接(可选) RUN sed -i 's/^bind-address\s*= 127.0.0.1/bind-address = 0.0.0.0/' /etc/mysql/mariadb.conf.d/50-server.cnf RUN cp /tmp/docker_entry.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/docker_entry.sh ENTRYPOINT [ "docker_entry.sh" ]
- 创建
init_db.sql文件:
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '${DB_ROOT_PW}'; GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '${DB_ROOT_PW}'; FLUSH PRIVILEGES;
- 修改
entrypoint.sh:
#!/bin/bash # 首次启动时初始化数据库 if [ ! -d /var/lib/mysql/mysql ]; then mysql_install_db --user=mysql --datadir=/var/lib/mysql fi # 前台启动MariaDB,保持容器运行 exec mysqld_safe
方案3:修复镜像构建时的密码持久化
如果坚持在RUN阶段设置密码,需确保权限表正确保存:
修改Dockerfile的RUN部分:
RUN service mariadb start && \ sleep 5 && \ mysql -u root -e "\ GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY 'root'; FLUSH PRIVILEGES; \ GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root'; FLUSH PRIVILEGES;" && \ service mariadb stop
添加sleep 5确保数据库初始化完成,再停止服务,让镜像保存正确的权限表状态。容器启动时entrypoint.sh只需启动服务:
#!/bin/bash service mariadb start tail -f /var/log/mariadb/mariadb.log
总结
核心问题是数据库启动的异步性,脚本执行命令时服务未完全就绪;错误提示的误导性源于服务未就绪时的验证逻辑异常。通过等待服务就绪、利用初始化脚本或确保镜像构建时权限表正确保存,均可解决问题。
内容的提问来源于stack exchange,提问作者bitdruid
相关产品推荐
相关产品推荐

