拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ClickHouse报错516全解析:认证失败排查与解决实践

ClickHouse报错516全解析:认证失败排查与解决实践 1. 先搞清楚516背后到底发生了什么1.1 一次典型的报错现场先说几句实在话。ClickHouse 里创建用户本身并不难难的是创建完之后你满心欢喜准备连上去跑个查询结果迎头撞上这么一句Code: 516. DB::Exception: Received from localhost:9000: DB::Exception: myuser: Authentication failed: password is incorrect, or there is no user with such name.凡是在生产环境里正经搞过 ClickHouse 的人大概率都见过这个 516。我第一次遇到它的时候第一反应是“是不是密码敲错了”反复核对确认没错又开始怀疑用户没建上。来回折腾了大半个小时最后发现用户确实是建上了只不过建到了“另一个地方”。这种绕圈子的经历我相信不是个例。今天这篇文章就把 516 这个错误从头到尾拆开讲清楚包括它为什么会用这么一句含糊的话当提示、创建用户的时候有哪些细节容易埋雷、以及真正高效的排查顺序应该是什么样的。1.2 错误码516的设计逻辑先把这个报错的本质说清楚。516 在 ClickHouse 服务端错误码表里对应的是 AUTHENTICATION_FAILED直译就是“认证失败”。它发生在你发起连接、服务端校验身份的那一步。这里有个值得注意的设计ClickHouse 故意把多种失败原因合并到同一个错误码和同一句提示里——密码错误、用户不存在、主机来源不被允许统统返回 516。这么做是安全上的考量。如果服务端针对不同的失败原因返回不同的提示攻击者就可以通过不断试探用户名根据返回差异来判断哪些用户是真实存在的这等于主动帮助暴力枚举。所以 ClickHouse 把所有认证信息相关的失败都收敛成同一句话。好处是攻击者拿不到有用的信息坏处就轮到我们运维来承担了排障的时候没法指望报错给你指路只能靠一套合理的排查顺序把可能性逐个排除。1.3 为什么这个报错特别坑516 最让人头疼的地方就是它的提示信息几乎不给方向。“password is incorrect, or there is no user with such name”这句话是设计上的故意模糊但它把至少三类完全不同的故障场景压到了一起第一类密码确实错了或者密码在创建之后被改过。第二类用户确实不存在——或者更准确地说在当前这个节点上不存在。第三类用户存在但连接来源的主机不在允许范围内包括 IP 网段限制和 host 关键字匹配不上的情况。这三类问题在实际运维里处理方式完全不同第一类要改密码或找回密码第二类要在正确的节点上建用户或同步用户第三类要调整 HOST 配置。但它们的报错长得一模一样。所以排查 516 的正确姿势不是盯着密码死磕而是按顺序去验证用户在这个节点上到底存不存在、存的密码类型是什么、当前连接来源 IP 是不是被允许、客户端和服务端版本协议是否兼容。后面的章节就按这个顺序展开。2. 创建用户的正确姿势与常见雷区2.1 SQL方式创建用户语法与默认行为ClickHouse 从 20.x 版本开始大力推行 SQL 化的访问控制管理最常用的就是 CREATE USER 语句CREATE USER dev_user IDENTIFIED BY dev_password_2024;这句看起来和 MySQL 挺像但里面藏着一个关键点IDENTIFIED BY 这个简写形式到底会把密码存成哪种类型。ClickHouse 的密码类型有四种plaintext_password、sha256_password、double_sha1_password、bcrypt_password。不同版本里 IDENTIFIED BY 的默认值并不一样早期为了兼容 MySQL 客户端协议默认是 double_sha1_password后来版本里默认行为又逐渐向 sha256_password 迁移。不同版本执行同一条 SQL底层存的哈希可能不同单纯的登录行为一般不受影响因为服务端知道自己的存储类型。真正容易出问题的是后面要讲到的“手动生成哈希”场景以及 SQL 定义和配置文件定义混用时的错位。我的建议是创建时显式指定密码类型不要依赖默认值CREATE USER dev_user IDENTIFIED WITH sha256_password BY dev_password_2024;这样不管集群里节点版本差异有多大行为都是确定的。创建用户的同时还可以带上 HOST 限制、profile、quota 等属性这些属性与认证失败的关系非常密切我会在 3.3 节单独展开。2.2 users.xml方式适合基础设施化管理的场景如果没有走 SQL 化访问控制用户也可以定义在配置文件里。默认的 users.xml 位于 /etc/clickhouse-server/ 下结构大致是这样clickhouse users dev_user passworddev_password_2024/password networks ip::/0/ip /networks profiledefault/profile quotadefault/quota /dev_user /users /clickhouse文件驱动方式有一套独立的生态逻辑。服务启动时读取配置修改之后要么重启服务要么执行 SYSTEM RELOAD CONFIG 让它重新加载。这种方式在管理规模比较大的服务器集群时反而更顺手因为配置即代码可以放进 Git 做版本管理用 Ansible 或 Puppet 这类工具分发下去每台机器的用户定义天然一致不存在“这个节点有、那个节点没有”的问题。文件里的 password 标签用的是明文也可以换成哈希值标签。注意users.xml 里原生支持的是 password_sha256_hex也就是 SHA256 的十六进制表示并不支持直接把 double_sha1 的哈希拿过来用。生成 SHA256 哈希很简单命令行执行echo -n dev_password_2024 | sha256sum把输出的一串十六进制填进password_sha256_hex标签即可。服务端在验证时会用客户端传来的明文密码计算 SHA256再和你填的哈希做比对。这里特别容易翻车的地方在于很多人会把“密码字段本身的哈希”再哈希一次结果填进去的永远对不上。2.3 SQL与XML混用两个存储系统的冲突当你既通过 SQL 的 CREATE USER 建了用户又在 users.xml 里定义了同名用户事情就开始变得微妙了。ClickHouse 的访问控制实际上有多个存储后端默认是本地的 SQL 化存储目录/var/lib/clickhouse/access/还有 users.xml 这个文件存储以及 memory、zookeeper 之类的特殊后端。同名用户在不同存储里都存在的时候加载顺序和优先级会决定到底哪个生效。结果常常出现“我以为我改的是这个用户实际上客户端命中的是另一个”的情况。排查时可以查系统表SELECT name, storage, auth_type FROM system.users WHERE name dev_user;如果看到的 storage 是 users.xml而你又明明记得自己用 CREATE USER 建过这个用户说明当前生效的其实是配置文件里的那个定义SQL 里建的那个要么没生效要么被覆盖掉了。这时候你再执行 ALTER USER 去改密码改的可能只是本地 access 目录里的那份实际登录仍然走 users.xml 里的旧配置516 自然跑不掉。我的建议非常直接一个环境里只选一种管理方式不要混用。如果团队习惯在线操作、权限粒度要求细那就全部走 SQL 化管理如果环境是配置分发驱动的那就全部收拢到 users.xml。混用只保留给 default 用户这种特殊场景普通人别去碰。3. 登录失败的完整排查路径3.1 用SHOW CREATE USER确认用户真实状态连接出现 516 之后第一件事不是盯着密码看而是找一个还有权限的通道进服务端看一眼。正常情况下你可以用 default 用户或者其他管理员账号执行SHOW CREATE USER dev_user;这条语句返回的是服务端“眼里”这个用户的完整定义包括密码类型、HOST 范围、profile、quota 等。注意它显示的是服务端实际存储的定义而不是你脑海里以为的定义。如果你连管理员账号都登录不上了那就只能直接去看配置文件和服务端日志。顺便提醒一个容易踩的坑system.users 这个系统表的列在不同版本里有差异有的版本有 auth_type 和 auth_params 列有的老版本还没有。查询之前可以先执行 DESCRIBE TABLE system.users 确认一下当前版本的列结构免得一条 SQL 报出不存在的列名给自己添乱。3.2 密码类型对齐plaintext / sha256 / double_sha1密码类型对不上是 516 最常见的原因之一。举几个我在实际运维中遇到的真实场景场景一用户在 users.xml 里用password_sha256_hex定义但填哈希的时候填错了计算方式结果无论输入什么明文密码都报 516。因为服务端会拿你输入的明文去算 SHA256再和你填的哈希做对比根本不可能匹配。场景二手工复制或者迁移过 access 目录里的用户存储文件导致 auth_type 被写成了 double_sha1_password而新版本的 clickhouse-client 默认走 sha256 密码的认证交互流程两边算法对不上握手阶段直接失败。场景三用户本身一切正常但密码在某个时间点被人执行过密码重置比如 ALTER USER dev_user IDENTIFIED BY 新密码而你还在用旧密码。排查的时候用这条 SQL 看类型SELECT name, auth_type FROM system.users WHERE name dev_user;auth_type 列会直接告诉你当前用户是哪种密码类型。如果服务端是 sha256_password客户端正常传入明文密码即可服务端会自动完成哈希和比对不需要你手算哈希。真正需要警惕的只有“自己生成哈希”的场景这也是我在 2.2 节特意强调的原因。如果你确认是密码问题重置密码要趁早ALTER USER dev_user IDENTIFIED WITH sha256_password BY new_pass_2024;重置完成之后用最小查询验证一遍再交付给业务方。3.3 主机限制从“用户不存在”的现象反查HOST配置516 最隐蔽的来源是 HOST 限制。用户创建时如果带了来源限制CREATE USER dev_user IDENTIFIED BY pwd HOST IP 192.168.1.0/24;当连接来自 192.168.2.x 时ClickHouse 会直接判定“当前连接不存在这个用户”报的还是 516。注意它绝对不会告诉你“IP 不在白名单里”因为来源主机也是认证信息的一部分同样被故意模糊处理了。排查时看 SHOW CREATE USER 输出里的 HOST 段落或者查询 system.users 表里的 host_ip、host_names 列。这里有个值得单独说的小细节HOST localhost 只匹配 127.0.0.1、::1 和本机主机名它不匹配局域网 IP也不匹配你为了图方便在 /etc/hosts 里加的那些主机别名。很多人本机用 clickhouse-client --host 127.0.0.1 连得好好的一换成机器的局域网 IP 就 516原因就在这里。内网里给服务账号分配 HOST 范围时我一般这么建议统一写网段比如 HOST IP 10.0.0.0/8或者干脆 HOST ANY不要写 localhost。localhost 这种严格语义只适合留给运维手工操作的本机账号。3.4 集群场景为什么别的节点上就是登录不了如果 ClickHouse 是集群部署还有一个非常容易踩的大坑SQL 创建的 user 默认只写在当前节点的本地 access 目录不会自动同步到其他节点。默认的 access_control_path 是本地磁盘路径不是 ZooKeeper 或 Keeper 的路径。所以你在 node1 上执行 CREATE USER dev_user任何连到 node2 的客户端照样报 516因为 node2 上根本没有这个用户。解决办法有三条路线按适用场景选第一条路线创建时用 ON CLUSTERCREATE USER ON CLUSTER cluster_name dev_user IDENTIFIED BY pwd;但要注意这只是在集群所有节点上把“创建”动作各执行了一遍。之后你在某个节点单独执行 ALTER USER 改了密码其他节点不会跟着变。所以集群里改用户属性要么每次都带 ON CLUSTER要么统一收敛到一个配置管理流程里。第二条路线把用户放到 users.xml通过配置分发工具同步到每台机器。文件驱动的集群一致性是最简单可靠的适合节点数量不多、用户结构相对固定的场景。第三条路线把 access_control_path 配置指向 Keeper 或 ZooKeeper让所有节点共享同一份访问控制存储。这个方案适合用户多、权限变更频繁的规模化场景但也额外引入了对协调服务的依赖运维复杂度会上升小集群没必要为了几个用户去背这个包袱。4. 常见问题速查与我的实操习惯4.1 高频问题对照表把这些年实际遇到过、以及在网上社区里看到的高频 516 场景整理成一张表方便你排查的时候对着看现象最可能的根因处理办法default 用户突然登录不上users.xml 被人改过或密码哈希配置出错检查 users.xml 里 default 用户节点确认密码与哈希新建用户在其他节点登录失败SQL 用户未同步到该节点用 ON CLUSTER 创建或改用 users.xml 分发本机能连远程一接就报516HOST 限制不匹配SHOW CREATE USER 检查 HOST 段调整网段范围客户端密码正确仍然516客户端与服务端版本差异大认证协商失败对齐 client 版本显式指定 sha256_password 类型改完密码依然516连接打到了另一台机器或负载均衡后端确认访问入口对应节点用 SELECT hostName() 自查手工改 access 文件后登录全乱绕过了 SQL 接口直接改存储文件对比 access 目录备份恢复后再统一变更入口这张表覆盖了我遇到过的绝大多数情况。如果你的现象不在表里也先别急按第 3 章的路径一步步走基本都能定位。4.2 三个经常被忽略的细节第一个是密码里带特殊字符。这个坑很实在你在命令行里执行 clickhouse-client --user dev_user --password 密码如果密码以 - 开头或者包含会被 shell 吃掉或转义的字符传进去的可能就是空密码或截断后的字符串结果自然是 516。建议使用 --password 这种等号形式或者干脆用环境变量 CLICKHOUSE_PASSWORD把密码从命令行参数里摘出去。第二个是 HTTP 接口的认证方式。ClickHouse 的 HTTP 端口默认 8123也要认证而且很多人只测了 native 协议忘了业务方可能走的是 HTTP。header 方式如下curl -X POST http://127.0.0.1:8123/ -u dev_user:密码 --data-binary SELECT 1也可以这样curl http://127.0.0.1:8123/?querySELECT%201 -H X-ClickHouse-User: dev_user -H X-ClickHouse-Key: 密码如果 HTTP 响应里出现 516排查思路和 native 协议完全一样重点仍然是用户存在性、密码类型、HOST 范围这三件事。第三个是客户端与服务端的版本差异。如果你是从非官方渠道拿的安装包比如某些离线包、Windows 构建包客户端和服务端版本容易存在差异。认证握手在极端情况下会因为协议版本不一致而失败表现也是 516。看到这里你应该能理解为什么我一直强调显式指定密码类型、对齐版本——这些都是为了把变量控制住少一点“不知道哪里冒出来的”故障。4.3 推荐养成的运维习惯有几个习惯是我个人的强制项写在这里供参考用户定义尽量走 SQL 并纳入版本管理DDL 脚本存进 Git 仓库在每台服务器执行后留存输出。建用户脚本里永远显式写 IDENTIFIED WITH sha256_password不依赖任何版本的默认行为。密码定期轮换轮换操作使用 ALTER USER 完成避免直接改配置文件造成各处不一致。至少保留一个具备完整管理权限的“救援”账号密码不要写进业务脚本的环境变量或启动参数里防止真的出问题时自己也进不去。集群环境里做用户变更前先跑一句 SELECT hostName() 确认当前会话落在哪个节点避免“我以为改了所有节点实际只改了当前节点”。5. 写在最后的一点个人体会516 这个错误我踩过好几次后来想明白了一个道理ClickHouse 的认证体系是“故意不友好”的——把所有失败原因收敛成一句话是为了安全但也意味着运维人员必须建立自己的一套排查顺序不能指望报错替你指路。把前面几步走完绝大多数 516 都能在几分钟内定位先确认用户存在性和密码类型再确认 HOST 范围再确认连接是否打到了正确的节点最后才轮到怀疑密码本身。另外如果你是从 MySQL 转过来的千万别套用“GRANT ALL PRIVILEGES ON.TO user”那种心智模型。ClickHouse 的用户、角色、权限、配额是分离的创建一个用户只是开始后面还要配 GRANT、profile、quota 和 settings。很多所谓“登录失败”的真实原因其实是用户建了但没授权应用层拿到的是访问被拒的错误被误当成 516 来排查。把“创建用户”和“授予权限”当成两个独立步骤会少走很多弯路。最后分享一个我一直在用的验证小技巧新建用户以后别急着让业务方去连先自己在命令行用最小查询验证一遍clickhouse-client --user dev_user --password 密码 --query SELECT 1返回 1 再交付比让业务方反复试错省时间得多。你如果也想少被 516 折腾建议把“创建、验证、授权”这三个动作固化成自己的上线检查清单每次照做一遍基本就不会再有“神秘登录失败”的故事了。
返回列表