You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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密码则无报错,但手动设密码后,重启容器必现该错误。

原因分析

  1. MariaDB启动异步性:service mariadb start是异步启动,脚本执行mysql命令时,数据库可能还未完成初始化,此时root用户的密码验证逻辑未就绪,导致报错。
  2. 镜像与容器状态差异:RUN阶段设置密码后,镜像保存的是静态文件系统,但容器启动时MariaDB会重新读取配置,若无正确初始化逻辑,会出现密码不匹配或验证异常。
  3. 错误提示误导性:报错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/目录下的脚本,通过这个机制配置密码更可靠:

  1. 修改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" ]
  1. 创建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;
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 09:37:19