Redis 设置密码无效这个问题我应该被问过不下二十次。最近一次是帮一个团队看测试环境redis.conf 里明明写着requirepass可redis-cli连上去直接就能读能写整个库等于裸奔。第一次遇到这种事的人十有八九会去怀疑配置文件语法、怀疑密码被注释、甚至怀疑 Redis 版本有 bug。但排障做多了以后我可以负责任地说绝大多数设置密码无效都不是 Redis 本身的问题而是配置加载、ACL 覆盖、持久化、客户端连接这几条链路里有一个环节没对上。这篇文章不打算讲高深原理只把这些年踩过的坑、处理过的真实案例以及一套可以直接照抄的排查流程完整写出来覆盖 Redis 5 到 Redis 7 的常见版本。无论是正在被密码问题折磨的运维、后端开发还是刚接触 Redis 想搞清楚认证机制的新手都能在里面找到对应自己场景的那一节。1. 密码设置无效之前先把现象分清楚设置密码无效听起来是一个问题实际是三类完全不同的现象每一类的排查路径都不一样。不先把现象定义清楚就上手改配置很容易在原地打转。1.1 三种典型的无效长相第一类改了配置文件、重启了 Redis结果不带密码照样能访问。这是字面意义上的无效通常指向配置文件没有被加载或者加载了但里面的指令没起作用。这篇文章后面要讲的配置来源问题、ACL 覆盖问题最终表现出来的都是这个现象。第二类设置了密码客户端反而连不上了或者动不动报错。这种无效其实是密码已经生效了但客户端认证方式不对。比如密码带特殊字符导致 shell 转义出错、客户端库还在用旧密码、连接串里用户名和密码写反了。问题出在密码的使用方不在设置方。第三类密码当时生效重启之后又没了。这类问题的根源几乎都是配置没有持久化比如只执行了CONFIG SET requirepass改了运行内存没写回配置文件或者写了配置文件但是进程重启时根本没有加载那个文件。要快速区分这三类一个动作就够了用redis-cli不带密码去 ping再带密码去 ping。不带密码 ping 返回PONG服务端当前没有开启认证属于第一类。不带密码 ping 返回NOAUTH Authentication required.认证已经生效属于第二类问题在客户端怎么连。不带密码 ping 返回Connection refused连接层面先挂了跟密码无关属于环境问题。带密码 ping 返回WRONGPASS服务端有密码但你给的密码是错的。1.2 两个假无效的陷阱还有一个容易绕晕的细节Redis 6 之后的认证体系改成了 ACL某些探测命令在没有认证时是否被拒绝取决于 default 用户的 ACL 状态。所以能 ping 通不等于服务端没密码ping 不通也不一定就是密码问题。遇到问题别急着下结论先记录现象再往下查。另一个陷阱是把CONFIG GET requirepass的结果当成唯一标准。在 Redis 6 里requirepass只是 default 用户密码的一种快捷配置方式如果你通过ACL SETUSER直接给 default 用户设置了密码某些场景下CONFIG GET requirepass看到的仍然可能是空值但认证其实已经开启。反过来配置文件里写了 requirepass运行时CONFIG GET也可能显示空因为那个文件根本没被加载。所以这一节的核心原则就一句话先定位现象再动手排查。把无效具体成免密可访问客户端认证报错重启后密码消失中的哪一类后面的排查才有方向。2. 服务端实测三条命令定位认证真实状态不管现象看起来多奇怪第一步永远是直接在服务端验证认证状态。因为只有服务端的行为是客观事实客户端报错里的信息经常具有误导性。2.1 三条命令看清认证状态我每次排查必用的三板斧是这样的# 1. 看运行时配置里的 requirepass redis-cli CONFIG GET requirepass # 2. 不带密码直接 ping redis-cli PING # 3. 带密码 ping redis-cli -a 你的密码 PING结果解读对照表如下操作返回结果结论CONFIG GET requirepassrequirepass后跟空串运行时没有设置 requirepassCONFIG GET requirepassrequirepass后跟密码值运行时已设置 requirepass不带密码 PINGPONG当前无需认证不带密码 PINGNOAUTH Authentication required.认证已开启带密码 PINGPONG密码正确带密码 PINGWRONGPASS invalid username-password pair密码错误或认证方式不对这里特别提醒CONFIG GET requirepass显示有值只代表运行时内存里有这个配置不代表配置文件里写了显示为空也不代表配置文件里没有。它只是运行时快照。配置文件里的内容到底有没有被加载要看下一节的 INFO 输出。2.2 INFO 输出里藏着真相INFO server段有一个字段叫config_file它直接告诉你当前进程是从哪个配置文件启动的redis-cli INFO server | grep config_file如果输出是config_file:/etc/redis/redis.conf说明进程确实加载了这个文件。如果输出是config_file:空值说明 Redis 是裸启动的没有任何配置文件。你在 redis.conf 里写 requirepass 写得再漂亮也是白搭因为那份文件它压根没读。这个字段是我排查密码无效时第一个看的东西。它一秒钟就能把配置文件没加载和配置加载了但没生效这两类问题分开省掉大量无效操作。2.3 容易误判成密码问题的连接报错还有一种报错经常被误当成密码无效当你从远程主机连接一台没有设置密码、又没有显式 bind 的 Redis 时服务端会返回DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is configured.这句报错里明确写了no authentication password is configured它的核心含义是服务端当前没有密码而且开启了保护模式。这个报错本身就是在告诉你你设置的密码没有生效或者根本没设置。看到它不要急着改防火墙先回到配置文件加载这条线路上检查。这一节的逻辑闭环是CONFIG GET 看运行时值PING 看实际认证行为INFO 看配置来源报错信息看链路方向。四个信息交叉之后问题基本能被压缩到很小的范围。3. 配置文件没被加载最常见的无效根源在所有Redis 设置密码无效的案例里配置文件没有被加载占的比例最高。而且这个原因隐蔽在很多人根本意识不到自己的启动方式和配置文件是脱节的。3.1 启动命令决定一切Redis 的默认行为是无密码启动。就算你往/etc/redis/redis.conf里写了 requirepass如果启动命令是下面这种redis-server那 Redis 用的就是内置默认配置你写的文件它没读。要让配置生效必须显式指定配置文件路径redis-server /etc/redis/redis.conf也可以临时用命令行参数指定密码这种方式优先级比配置文件更高适合快速验证但一个致命的缺点是进程重启后参数就丢了不适合作为长期方案redis-server --requirepass YourStrongPassword!2024为什么我反复强调启动命令因为实际翻车的案例里很多人习惯先手动执行redis-server起一个实例做验证验证完不关后面又用 systemd 或部署脚本起了另一个带配置的实例。两个实例同时监听redis-cli 默认连的是那个裸启动的自然表现得密码无效。这种多实例互相干扰的情况光改配置是永远解决不了的。我现在养成了一个习惯凡是涉及 Redis 的操作起服务之前先执行ps -ef | grep redis-server看一遍确认没有旧实例占用端口。3.2 systemd 与 Docker 场景的配置路径Linux 发行版通过包管理器安装的 Redis一般会带 systemd 服务默认配置文件路径通常是/etc/redis/redis.conf。systemd 启动时会把这个路径作为参数传给 redis-server所以你改完文件后执行systemctl restart redis就能生效。注意 Debian 系和 RHEL 系的包路径可能有差异不确定时用文章开头讲的INFO server查配置来源。Docker 是重灾区。官方 redis 镜像的默认启动命令是redis-server不带任何配置文件。如果你只把宿主机上的配置文件挂载进容器不修改启动命令那容器里跑的依然是裸启动的 Redis# 错误做法配置挂进去了但启动命令没有使用它 docker run -d \ -v /data/redis/redis.conf:/usr/local/etc/redis/redis.conf \ redis:7正确做法是把配置文件路径写进启动命令docker run -d \ --name redis \ -p 6379:6379 \ -v /data/redis/redis.conf:/usr/local/etc/redis/redis.conf \ redis:7 \ redis-server /usr/local/etc/redis/redis.conf容器里排查更容易绕晕因为一些镜像或编排平台会在启动脚本里注入环境变量、覆盖部分配置。我的经验是进容器先执行redis-cli INFO server看清楚 config_file 到底是什么再用ps -ef | grep redis-server看启动参数最后才去检查挂载的配置文件内容。顺序反了很容易查错文件。3.3 配置文件里的低级但高频错误配置文件被加载了requirepass 依然没生效还有一种可能是那一行压根没写对。常见错误有这么几类行首有#整行被注释掉了。很多人喜欢注释旧配置再追加新配置结果注释符没删干净。指令名拼错比如写成require-pass、requirePass、password。Redis 配置项解析时不会因为你拼错就报错它只会把不认识的行忽略掉。同一个文件里有多个 requirepass后面的覆盖前面的。配置很长的时候前面设了密码后面某处又设了一次空值或者别的值。密码带引号的问题在 redis.conf 里requirepass后面整行内容都是密码的一部分。写成requirepass abc真实密码是包含双引号的abc而不是 abc。客户端如果按 abc 去认证永远过不去。配置不长的前提下一个 grep 就能把这些问题全揪出来grep -n ^[[:space:]]*requirepass /etc/redis/redis.conf看输出里的行号和行内容注释、拼写、重复覆盖一目了然。还有一个实用技巧改完配置不放心可以在前台跑一次redis-server /etc/redis/redis.conf它会直接把启动日志打到终端配置语法有问题时会明确报错。确认启动正常再CtrlC停掉回退到原有的启动方式。4. Redis 6 的 ACL 机制requirepass 被静默覆盖的真相如果你确认配置文件加载了、requirepass 也写对了但密码依然不生效尤其是 Redis 6 以上的版本那就要把注意力转到 ACL 上。这是最隐蔽、也最容易让人怀疑人生的一类问题。4.1 requirepass 在 ACL 体系里的真实身份Redis 6 引入 ACL 之后认证机制发生了根本变化。在旧版本里requirepass 是一个独立的全局配置在 Redis 6 里requirepass 本质上是给 default 用户设置密码的一种快捷写法。你写requirepass foobarRedis 内部等价于把 default 用户的认证方式设置为必须使用密码 foobar。这个转变带来的影响是决定是否需要密码的最终依据不是 requirepass 这个配置项而是 default 用户的当前 ACL 状态。requirepass 只是修改 default 用户状态的一种手段不是唯一手段。4.2 user default nopass 的覆盖场景很多新版本 Redis 自带的示例配置文件或者网上流传的最佳实践配置里会有这么一行user default on nopass ~* all这一行的意思是default 用户开启免密码可以访问所有 key可以执行所有命令。它本身是为了初始化方便但如果你在配置文件里既有requirepass又有这行user default on nopass最终谁生效取决于它们在文件里的顺序。Redis 加载配置时是顺序处理的。当它遇到user default on nopass会把 default 用户重新设置为免密如果这一行出现在 requirepass 后面那前面设置的密码就会被覆盖掉。结果就是你打开配置文件requirepass 明明写得清清楚楚但运行时 Redis 完全没有密码要求。我自己就踩过这个坑。当时拿了一份高版本 Redis 的示例配置里面默认带了user default on nopass我在后面追加了 requirepass以为密码稳了。结果测试环境里免密随便连查了很久才发现是配置顺序的问题。从那以后我养成了习惯凡是 Redis 6 以上的实例判断密码是否生效只看 ACL 的实际状态不看配置文件表面。修复方法有两种。一是把配置文件里的 requirepass 和user default on nopass收拾利索只保留一个认证方式二是改用明确的 ACL 写法把密码和权限一次性定义清楚user default on YourStrongPassword!2024 ~* all注意前缀表示给用户设置密码nopass表示免密这两个在同一行里是互斥的。混着写会出现难以预料的覆盖行为不要这么干。4.3 用 ACL 命令确认并修复Redis 6 排查认证问题不能只看CONFIG GET requirepass要看 ACL 的真实状态# 查看 default 用户当前配置 redis-cli ACL GETUSER default # 查看所有用户的 ACL 规则 redis-cli ACL LISTACL GETUSER default输出的 flags 字段里如果包含nopass说明 default 用户现在免密requirepass 确实没起作用。如果 flags 里没有nopass并且带有了密码配置那认证就是开启状态问题在别的环节。临时修复可以执行redis-cli ACL SETUSER default YourStrongPassword!2024这条命令会把 default 用户的密码设置为指定值同时移除 nopass 标志效果上等同于设置 requirepass而且即时生效不需要重启。但要注意它同样只改运行内存状态想持久化还是要配合CONFIG REWRITE或直接改配置文件。另外Redis 6 里CONFIG SET requirepass依然可用内部也是调用 ACL 改 default 用户的密码。所以不用纠结用哪种方式重点是理解它们最终都在修改同一个目标default 用户的认证状态。5. 改密与持久化CONFIG SET 和 CONFIG REWRITE 的边界前面几节解决了密码不生效的问题这一节要处理的是密码生效了但一重启就消失。这类问题的核心是理解 Redis 配置的运行时修改和持久化之间的关系。5.1 CONFIG SET 只是临时生效很多人为了快速验证会直接在线上执行redis-cli CONFIG SET requirepass YourStrongPassword!2024执行完发现没密码连不上了以为大功告成。但这个操作只改了运行内存里的配置没有写回任何文件。一旦 Redis 重启、进程崩溃、容器重建密码立刻消失回到免密状态。这就是重启后密码无效这类问题的标准答案。线上 Redis 如果一度处于没有密码的状态临时CONFIG SET加密码只能算应急手段。应急之后必须马上把配置文件改好并且确认持久化生效否则哪天半夜实例自动重启数据又回到裸奔状态。5.2 CONFIG REWRITE 的条件和注意点redis-cli 提供了CONFIG REWRITE命令可以把当前运行配置持久化回配置文件redis-cli -a YourStrongPassword!2024 CONFIG REWRITE但它有一个硬性前提当前 Redis 进程必须是从配置文件启动的。如果是裸启动CONFIG REWRITE会直接报错ERR The server is running without a config file这个报错其实就是第 3 节问题的另一种表现形式。看到它先回到启动命令那一环去解决。还有一种情况进程有配置文件但文件在磁盘上不可写或者容器里以只读方式挂载了配置文件CONFIG REWRITE也会失败。所以持久化之前建议先确认路径和权限redis-cli INFO server | grep config_file ls -l /etc/redis/redis.conf另一个实际运维中容易忽略的细节CONFIG REWRITE会把当前所有运行时的有效配置都重写进文件相当于把文件的格式和注释全部重排一遍之后做配置 diff 会比较混乱。如果团队有配置审计需求更稳妥的做法是手动编辑配置文件、然后重启 Redis而不是依赖CONFIG REWRITE。5.3 改密后的连接与安全注意改密这个动作还有个容易被忽略的后果已经建立的连接怎么办。Redis 的认证是连接级的客户端连接一旦通过 AUTH这个连接就带有认证状态。修改密码之后已经通过旧密码认证的连接通常还能继续使用新连接才必须用新密码。这会造成一种奇怪的中间状态看起来 Redis 一部分流量需要密码、一部分不需要。如果应用侧的连接池还持有旧连接短时间内可能一切正常一旦连接被回收重建就会开始批量报认证失败。所以改密不是改完就收工还要把应用端的连接配置一起更新并做好连接池的平滑替换。我建议的操作顺序是先更新应用配置再改 Redis 密码然后滚动重启应用实例最后观察日志确认没有认证错误。另外安全习惯也要纠正一下用redis-cli -a这种方式验证密码密码会明文出现在 shell 历史里也可能被进程列表里的其他用户看到。临时验证可以用长期运维建议通过环境变量、配置管理工具或客户端库的认证参数传递别把密码硬编码在脚本里。配置文件里的 requirepass 同样是明文记得把/etc/redis/redis.conf的权限设成 600并且用专门的系统账号运行 Redis。6. 客户端侧被忽视的坑特殊字符、连接池与实例混淆服务端密码完全正常客户端却一直报认证失败这类问题排查起来容易被绕进去因为报错信息五花八门。这一节把我在客户端侧遇到过的高频问题集中说一下。6.1 客户端认证写法里的常见错误第一个要检查的是密码本身。很多密码带$、!、或空格在 shell 里直接写会产生意外行为# 密码带 $ 时$ 会被 shell 当成变量展开 redis-cli -a abc$123 PING这类情况要么用单引号把密码完整包起来要么用环境变量传入或者直接在交互模式里执行 AUTHredis-cli AUTH YourStrongPassword!2024对于客户端库常见错误是连接参数里把用户名和密码写反或者在 Redis 6 环境里只传密码但没传用户名。Redis 6 的默认用户名是 default多数客户端库会自动补上但一些旧版本库不认识 ACL走的是老式 AUTH 流程需要单独看库文档确认参数名。6.2 连接池缓存旧密码生产环境里还有一种特别隐蔽的情况连接池还在用旧密码。很多连接池的设计是启动时建立一批连接之后复用。你改了 Redis 密码但应用没重启连接池里的连接还活着它们继续用之前认证通过的连接跑命令看起来一切正常。等这批连接被服务端断开或者池子触发重建新连接用旧密码去认证就会批量报错。这种问题的典型表现是改密码后半小时内一切正常之后突然出现大量认证失败过一会儿又自己恢复。排查时不要只盯着 Redis 服务端日志应用日志里的认证错误时间点往往能帮你定位到连接池重建事件。我的建议是改密码要像发布版本一样对待。先把新密码写到配置中心或应用配置里滚动重启应用等新连接全部建立成功再切换 Redis 密码最后观察一段时间没有报错才算完成。6.3 端口、实例与环境混淆最后说一个最笨但最常见的错误你连的根本不是你以为的那个 Redis。比如本机 redis-cli 连 127.0.0.1:6379 验证是正确的但应用服务器连的是内网 IP 或另一个端口。如果机器上有多个 Redis 实例或者云厂商还挂了一个托管 Redis那你配置文件的密码写对也没用对方认的不是这份配置。排查工具很简单三个命令一起看# 当前连的实例是谁 redis-cli INFO server | grep -E redis_version|config_file|tcp_port # 本机监听了哪些端口 ss -lntp | grep 6379 # 防火墙是否放行对应端口 iptables -L -n | grep 6379如果应用连的是云托管 Redis那它有自己的密码体系和自建实例的 requirepass 完全无关。你在本地配置文件里写到天上去也影响不到它。这种场景下设置密码无效的本质是密码设置错了实例已经不是 Redis 配置机制的问题了。7. 可以直接抄的排查清单与收尾习惯文章写到这里核心问题基本覆盖完了。为了方便你下次遇到Redis 设置密码无效时少走弯路我把整套排查思路压缩成一份清单按顺序执行即可先分现象免密可访问、客户端认证报错、重启后失效属于哪一类。确认连的是哪个实例redis-cli INFO server看 redis_version、config_file、tcp_port再用ps -ef | grep redis-server和ss -lntp交叉验证。看运行时认证状态CONFIG GET requirepass、不带密码 PING、带密码 PING。检查配置来源config_file 是否有值为空就是裸启动配置文件没被加载。检查配置文件内容grep 出所有 requirepass 行确认没有注释、没有拼写错误、没有重复覆盖。Redis 6 额外检查 ACLACL GETUSER default看 flags 是否包含 nopass看配置里user default是否覆盖了 requirepass。验证密码正确密码 AUTH 返回 OK错误密码返回 WRONGPASS未认证执行普通命令返回 NOAUTH。检查持久化确认修改写进了配置文件或者CONFIG REWRITE执行成功。检查客户端密码有无特殊字符、连接池是否用了旧密码、连接串是否指向正确实例。改密后收尾更新应用配置、滚动重启应用、观察日志确认无认证错误。这套清单我基本每次排查都在用顺序不能乱。先环境后配置、先服务端后客户端每一步只做判断不下结论几乎不会漏掉问题。最后分享一个个人习惯凡是碰过 Redis 密码相关配置我都会顺手在运维文档里记一笔——当前实例的配置文件路径是什么、从哪个进程启动、密码最后修改时间是什么时候。很多时候设置无效之所以折腾几个小时不是问题多难而是根本不知道线上那个 Redis 是怎么被拉起来的。把启动方式和配置文件路径对应清楚这个领域的坑至少能少踩一半。