我第一次认真排查“Redis 设置密码无效”这个问题,是在一次压力测试任务里:测试同事跑完一轮后,很平淡地给我丢了一句“你配的密码好像没生效啊,我无认证直接读到 key 了。”我当时第一反应是打开 redis.conf 翻了个底朝天,确认 requirepass 写得没问题,单词也没拼错,服务也重启过了,可客户端就是能不带密码直连。
后来被一位搞了十几年 Redis 运维的老哥一句话点醒:别猜了,先看这个进程到底是从哪份配置起来的。
绝大部分“requirepass 设置无效”根本不是 Redis 本身的问题,而是 Redis 进程压根没加载你以为的那份配置。这篇文章我按自己这些年排障的真实顺序来写:先讲怎么查“进程到底加载了什么”,再讲 ACL 和 requirepass 的联动坑,最后把 systemd、Docker、Windows 这种部署方式下配置被“吞掉”的典型场景一并拆开。文章里给出的命令和步骤,都是可以直接照抄去现场验证的。
1. 一切“无效”的根源:Redis 没有加载你改的那份配置文件
1.1 动手第一步:看启动命令,别先看配置
很多人习惯性拿到问题就去编辑器里翻 redis.conf,这其实是最容易走弯路的一步。配置文件写完,Redis 到底加载没加载,完全取决于启动命令里带的参数。看一个例子的反面效果:
bash复制# 你改的文件路径
/etc/redis/redis.conf
# 但实际启动命令可能是这样
redis-server
# 或者这样
redis-server --port 6390
# 或者这样
redis-server /usr/local/etc/redis.conf
这三种情况里,只有最后一种会加载 /etc/redis/redis.conf 或 /usr/local/etc/redis.conf。前两种要么使用默认配置,要么只加载命令行里出现的配置路径。Redis 在没有任何配置文件参数启动时,会使用内置默认参数,此时 requirepass 为空,你改再多文件它也不会读。
所以我的第一条建议是:排障时先看进程,再看文件。在 Linux 上直接用 ps 查:
bash复制ps -ef | grep redis-server
正常输出类似:
bash复制redis 3456 1 0 Jul12 ? 00:00:12 /usr/local/bin/redis-server 127.0.0.1:6379
如果最后只给了监听地址,没有配置文件路径,就是问题信号之一。更全的启动信息可以这样看:
bash复制cat /proc/3456/cmdline | tr '\0' ' '
这个命令会把进程的完整启动参数原样打出来,比看 ps 截断后的输出更可靠。
1.2 用 redis-cli 反查实际生效配置
如果 Redis 已经跑起来了,没必要去跟启动脚本猜谜,直接在客户端里查就好。最核心的命令是:
bash复制redis-cli info server | grep -E "config_file|redis_version"
这能看到当前进程加载的配置路径和版本信息。如果 config_file 显示为空,或者显示的不是你编辑的那个路径,那问题基本上就定位了:你改错了文件。
再看 requirepass 的实际生效值:
bash复制redis-cli config get requirepass
如果返回这样:
bash复制1) "requirepass"
2) ""
那就明确表示当前进程没有密码。此时不要再纠结配置文件里写了什么,而是去查启动命令和服务脚本,搞清楚为什么你说的那份配置没有进入进程。
换个方向,如果 config get requirepass 能返回你设置的密码,但客户端仍然不需要验证就能读数据,那问题就进入下一类:ACL 配置把 requirepass 的“默认用户密码”效果覆盖了。这部分我放在第 3 章细讲。
1.3 配置文件里的换行、引号与小坑
文件路径正确,不代表配置内容就没问题。我处理过的真实案例里,有一种非常隐蔽的坑:配置文件本身语法没报错,但密码没有按预期写进去。
比如这样:
ini复制requirepass MyPass
看起来没毛病。但如果是用 echo 追加的方式生成配置,很容易在文件末尾带出一个不可见字符:
bash复制echo "requirepass MyPass" >> /etc/redis/redis.conf
这个写法本身没问题。问题往往出现在密码里带了特殊字符,比如 $、#、空格。Redis 配置文件解析时,密码建议用引号包起来:
ini复制requirepass "My#Pass@2024!"
不包引号的情况下,有些版本会把 # 后内容当成注释,有些配置管理工具在按行读取时碰到空格会截断,结果密码不是你想的那个值。排障时我会把 requirepass 先设成纯数字或纯字母,验证链路通了再换复杂密码,这样能快速区分是配置格式问题还是密码匹配问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. requirepass 的“假无效”:运行时改了没持久化,AUTH 又用错了姿势
2.1 当 Redis 真的没设密码时,AUTH 会给出什么信号
有一种情况是你确实执行过设置密码的命令,但碰到客户端工具返回的问题,会让人误以为密码无效。我先说一个很快的判定方法:
bash复制redis-cli -p 6379
127.0.0.1:6379> auth mypassword
(error) ERR Client sent AUTH, but no password is set. Did you mean AUTH <username> <password>?
注意 no password is set 这个报错。它不是说密码不对,而是说当前这个 Redis 实例根本没有设置密码。也就是说,现场返回值都替你证明了:requirepass 没有进到当前进程里。
反过来,如果你已经设置了密码,还执行不带密码的命令,会看到:
bash复制127.0.0.1:6379> keys *
(error) NOAUTH Authentication required.
这两种报错要严格区分。NOAUTH Authentication required 表示有密码但你还没认证;AUTH ... but no password is set 表示实例无密码可认证,你该检查的是配置加载问题。
2.2 运行时改了密码,重启后丢了的真实现场
运行时用 CONFIG SET 改密码也是常见的操作,不少人在排查过程中会顺手执行:
bash复制redis-cli -p 6379 config set requirepass "MyPass"
这条命令一旦执行,内存里的配置会立即生效。注意:它只改了运行中的 Redis,不会自动写回配置文件。紧接着再用 redis-cli keys * 测试,会提示 NOAUTH,当时看起来完全成功。但一旦 Redis 重启,内存配置清空,系统重新读取配置文件,密码又没了。于是用户得到“设置密码无效”的结论。
正确的做法是把 CONFIG SET 和 CONFIG REWRITE 一起用:
bash复制redis-cli -p 6379 -a "MyPass" config set requirepass "NewPass"
redis-cli -p 6379 -a "NewPass" config rewrite
CONFIG REWRITE 会把当前内存里的配置同步写回磁盘上 Redis 正在使用的配置文件。如果返回 OK,说明持久化成功。如果报错或者回显为空,优先检查运行 Redis 的系统用户对配置文件有没有写权限。Redis 进程如果是低权限用户启动,而配置文件属于 root 且不可写,rewrite 就会失败。这也算一个很经典的“配置貌似生效,重启就没”的原因。
2.3 客户端 AUTH 的对象是“每个连接”,不是“整个服务”
还有一类误判来自 Redis 的认证模型。Redis 的密码认证是连接级的。你在这个 redis-cli 会话里 AUTH 通过了,不代表另起一个新连接能免认证。不少人在第一个会话里验证了密码好用,然后在另一个终端或另一台机器上直接连,发现还是要密码,就怀疑“密码设置无效”,其实这是正常的。
如果用的是 Redis 6 及以上版本,还支持带用户名认证:
bash复制redis-cli auth default MyPass
因为 requirepass 本质上是给 default 用户设置密码,所以显式带上用户名更稳妥。这种写法在 Redis 7 里特别常见,也避免了某些客户端把密码当用户名使用带来的混淆。
3. Redis 6/7 的 ACL 和 requirepass,为什么“两套配置会打架”
3.1 requirepass 只是 default 用户的快捷方式
Redis 6 引入 ACL 之后,requirepass 这个配置在底层会被映射成“给 default 用户设置密码”。官方文档里写得很明白:requirepass 就是 default 用户的用户密码配置入口。
换句话说,如果你在 Redis 6/7 里还单独维护了一套 ACL 用户的配置,那么可能出现“requirepass 设置了,但某个自定义用户仍然不用密码”的情况。因为 requirepass 只控制 default 用户,不控制其他 ACL 用户。
如果你是用 Redis 7 的配置,并且拉起了自定义用户:
ini复制user worker on >WorkerPass ~cache:* +get +set
那么客户端用 AUTH worker WorkerPass 连接后,会不会受 requirepass 影响?答案是不会。这个 worker 用户有自己的密码体系。你单独改 requirepass,自然影响不到它。很多开源管理平台、跳板机里配置的连接账号,走的都是自定义 ACL 用户,所以普通用户会觉得“Redis 密码改了没反应”。
3.2 用 ACL GETUSER 检查 default 用户状态
定位这类问题,靠 CONFIG GET requirepass 还不够。我再补一条命令:
bash复制redis-cli -p 6379 acl getuser default
这条命令会列出 default 用户的完整权限和认证信息,包括 nopass 标记。如果输出里有 nopass,说明 default 用户被设置为“不需要密码”,那么你配置文件里写的 requirepass 不会起拦截作用。这是一个非常容易被忽略的叠加坑。
解决办法不是继续调 requirepass,而是直接在 ACL 层操作:
bash复制redis-cli -p 6379 -a "MyOldPass" acl setuser default on >MyNewPass
在 Redis 6+ 的 ACL 体系里,推荐的做法是:所有密码相关的改动都走 ACL 命令,不要配置文件里一套、运行命令里一套。 一旦两边都写了,而又出现 nopass 之类更宽松的标记,ACL 配置的优先级会把 requirepass 的效果压下去。
3.3 主从复制场景还要记得 masterauth
顺带说一个和 requirepass 强相关、但容易让人误以为“密码失效”的场景:主从复制。主节点设置了 requirepass 后,从节点必须配置 masterauth,否则从节点会一直尝试连接主节点但认证失败,复制迟迟不同步。
ini复制# 主节点
requirepass "MasterPassword"
# 从节点
replicaof 192.168.x.x 6379
masterauth "MasterPassword"
不少用户在主节点设完密码后,发现从节点数据不更新,第一反应是“复制功能被密码搞坏了”,还有人会反过来怀疑“密码根本没设对”。实际只是从节点欠了 masterauth。这类问题在 Docker 部署的主从环境里更常见,因为很多人容器起来之后根本没把 masterauth 写进去。
4. 部署形态在“偷偷换配置”:systemd、Docker、Windows 各有各的坑
4.1 systemd 服务文件里的 ExecStart 才是真正的权威
现在多数 Linux 发行版用 systemd 管理 Redis 服务。就算你手动改 /etc/redis/redis.conf,如果服务文件里指向的是另一份配置,或者启动了额外参数,那一切修改都可以不生效。先看服务定义:
bash复制systemctl cat redis-server
重点看 ExecStart 那一行。以常见的 Ubuntu/Debian 为例:
ini复制ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf
如果它指向的路径不是你修改的文件,那么你改别的配置文件当然无效。还有一种情况是 ExecStart 里没有显式指定配置文件:
ini复制ExecStart=/usr/local/bin/redis-server --supervised systemd --port 6379
这时 Redis 使用的内置默认参数,配置文件里的 requirepass 根本不会参与。你需要修改 unit 文件,把配置文件路径加进去,或者确保所有关键参数都写进 unit 文件本身。每次改完 unit 文件后,记得:
bash复制systemctl daemon-reload
systemctl restart redis-server
4.2 Docker 部署里最常见的三个“不生效”姿势
Docker 里遇到“requirepass 设置了但没生效”,我总结下来基本是三种情况。
第一种,宿主机的 redis.conf 没有挂载进容器。很多人以为把宿主机某个 redis.conf 改了就能影响容器,但容器默认不会读宿主机文件。官方 redis 镜像指定的默认配置文件路径是 /usr/local/etc/redis/redis.conf,如果你不通过 -v 挂载进去,它就走镜像内的默认配置。
第二种,docker run 通过命令行传参覆盖了文件配置。就算你挂载了 contenful 文件,但 command 又带了 redis-server --requirepass anotherpass,命令行参数优先级高于配置文件,这也是“文件里是 A 密码,实际生效 B 密码”的典型来源。
第三种,用了 Bitnami 之类的封装镜像,却去改 requirepass。这类镜像通常有专门的环境变量,比如 REDIS_PASSWORD,它会由启动脚本注入配置。你在外部写 redis.conf 没用,得改环境变量:
yaml复制# docker-compose 示例
redis:
image: bitnami/redis:latest
environment:
- REDIS_PASSWORD=MyPass
所以 Docker 里定位密码问题,先执行:
bash复制docker exec -it redis redis-cli config get requirepass
docker inspect redis --format '{{.Config.Cmd}}'
docker inspect redis --format '{{json .Mounts}}'
三行命令看下来,配置来源基本就清楚了。
4.3 Windows 和 macOS 安装包的配置文件路径差异
Windows 上跑 Redis 的情况有点特殊,因为官方其实只提供 Linux/Unix 的发布版,Windows 上通常是用第三方编译版或 Memurai 这类兼容实现。很多人下载 zip 解压后,发现里面既有 redis.windows.conf,也有 redis.windows-service.conf,并且两个文件内容不完全一样。
如果 Windows 服务是用 redis.windows-service.conf 注册的,你只改了 redis.windows.conf,服务重启后密码照样无效。排障时先用系统服务命令查看实际启动路径:
bash复制sc qc Redis
看输出里的 BINARY_PATH_NAME,它会明确告诉你服务用的哪个配置文件。macOS 用 Homebrew 安装 Redis 后,默认配置路径是 /opt/homebrew/etc/redis.conf(Apple Silicon)或 /usr/local/etc/redis.conf(Intel)。如果你习惯把配置写在 /etc/redis.conf,同样会造成“改了密码但服务不认识”的情况。
5. 密码配置成功之后:一套可以照抄的自检流程
5.1 三步定位:启动参数、实时配置、ACL 状态
我把这套流程完全写出来,可以直接按顺序执行:
bash复制# 第一步:确认当前进程从哪来
ps -ef | grep redis-server
# 第二步:确认实时配置里的密码
redis-cli -p 6379 config get requirepass
# 第三步:确认 default 用户没有被 nopass 覆盖
redis-cli -p 6379 acl getuser default | head -20
如果第二步返回的密码与你预期一致,第三步也没有 nopass,那配置层面的工作已经完成了。剩下要验证的就是连接链路本身。
5.2 用正反两个方向验证 AUTH
密码设置成功后,我习惯同时做“正向认证”和“反向认证”两组测试:
bash复制# 正向:正确密码应该返回 PONG
redis-cli -p 6379 -a "MyPass" ping
# 反向:错误密码应该被拒绝
redis-cli -p 6379 -a "WrongPass" ping
正向返回:
bash复制PONG
反向应该报:
bash复制(error) WRONGPASS invalid username-password pair or user is disabled.
同时再验证一下未认证状态:
bash复制redis-cli -p 6379 ping
(error) NOAUTH Authentication required.
如果三条结果都符合,说明 Redis 本身对密码的强制要求已经完全生效。注意,如果不喜欢在命令行明文带密码,可以使用环境变量或交互式 AUTH。为了减少 shell 历史记录暴露密码的风险,也可以在命令前加空格执行,或者用完 history -d N 清理掉下一条记录。
5.3 别再忘的收尾动作:CONFIG REWRITE 与 protected-mode
业务上线前,有几个容易被忽略的收尾配置要一并检查。
第一,CONFIG REWRITE。如果你是通过 CONFIG SET requirepass 改的密码,一定要执行一次 rewrite 做持久化。这里有个经验:rewrite 失败通常是权限问题,Redis 系统用户对配置文件无写权限时,它会提示错误而不是默默忽略。看到错误是好事,至少你能知道原因。
第二,protected-mode。Redis 默认情况下 protected-mode yes,如果 Redis 只是绑定了内网或 127.0.0.1,外部客户端即使有密码也可能连不上。如果监听在公网地址,更要确认 bind 和防火墙策略,避免出现“密码设置没问题,但端口裸奔在公网”的情况。
bash复制redis-cli -p 6379 -a "MyPass" config get protected-mode
redis-cli -p 6379 -a "MyPass" config get bind
第三,密码长度和复杂度。限于 Redis 本身的性能定位,密码认证逻辑很快,但你不能因此就设个 123456。生产环境里建议直接用随机长密码:
bash复制openssl rand hex 32
把生成的 64 位十六进制字符串写入 requirepass。既避免弱口令,也减少被字典扫描的风险。
踩过这个坑之后,我现在排查任何 Redis 认证类问题都先习惯性问自己三个问题:这个进程从哪里启动?它加载的配置文件路径是什么?有没有其他用户体系在覆盖 default 用户的认证状态?把这三个问题跑完,九成“设置密码无效”的问题都能当场闭环,剩下的才是真正需要翻源码或者看网络抓包的极端场景。
