530 Login incorrect 的根本原因通常是 PAM 或 shell 限制:/etc/shells 缺失用户 shell、pam_shells.so 配置错误或用户 shell 为 /sbin/nologin 且未配 allow_writeable_chroot。

vsftpd 报 530 Login incorrect 但密码确实正确
这是 vsftpd 最典型的“假失败”:用户能正常 ssh 登录,passwd 验证无误,但 FTP 就是拒绝。根本原因几乎都出在 PAM 或 shell 限制上,而非密码本身。
/etc/shells 文件里没加 ftp 用户的 shell
vsftpd 默认启用 check_shell=YES(尤其在 RHEL/centos 系统),它会严格检查用户 shell 是否列在 /etc/shells 中。哪怕你用 /bin/bash,如果该路径没被显式写入 /etc/shells,登录就直接被 PAM 拒绝,日志里只显示模糊的 530。
实操建议:
- 运行
cat /etc/shells确认目标 shell(如/bin/bash、/bin/sh)是否在列表中 - 若缺失,用
echo "/bin/bash" >> /etc/shells追加(注意权限,需 root) - 改完不用重启 vsftpd,PAM 会实时读取
- 临时验证可先设
check_shell=NO测试,但不推荐长期关闭
PAM 配置误启了 pam_shells.so 或顺序错乱
很多系统默认的 /etc/pam.d/vsftpd 包含 auth [success=ignore default=bad] pam_shells.so 这类规则——它和 /etc/shells 联动,但失败时不输出具体原因,只让 vsftpd 返回 530。
常见错误场景:
- 手动修改过 PAM 文件,把
pam_shells.so放到了pam_unix.so前面,导致还没校验密码就因 shell 检查失败而终止 - 使用了第三方 vsftpd 包(如某些 docker 镜像),PAM 配置自带冗余限制
-
/etc/pam.d/vsftpd不存在,系统 fallback 到/etc/pam.d/ftp或通用配置,行为不可控
建议动作:
- 确认
/etc/pam.d/vsftpd存在且内容简洁,核心 auth 行应类似:auth [default=ignore] pam_succeed_if.so user != rootauth required pam_unix.so - 注释掉所有带
pam_shells.so的行,或确保它出现在pam_unix.so之后(仅用于 post-auth 检查) - 开启 vsftpd 调试:在
/etc/vsftpd.conf加log_ftp_protocol=YES+xferlog_enable=YES,再看/var/log/vsftpd.log
用户 shell 被设为 /sbin/nologin 或 /bin/false 但未配 allow_writeable_chroot
为安全把 ftp 用户 shell 设成 /sbin/nologin 是常见做法,但这会让 vsftpd 在 chroot 前就拒绝登录(尤其启用 chroot_local_user=YES 时)。错误不是发生在认证阶段,而是 session 初始化环节。
关键点:
-
/sbin/nologin和/bin/false不在/etc/shells中 —— 即使你加了,vsftpd 也可能因内部逻辑跳过 - 若坚持用非登录 shell,必须同时满足:
•chroot_local_user=YES
•allow_writeable_chroot=YES(注意:这有安全风险,仅限私有环境)
• 用户主目录不能有写权限(vsftpd 会检查ls -ld /home/ftpuser) - 更稳妥的做法是用
/bin/bash+sudo usermod -s /bin/bash username,再通过chmod 755 /home/username控制目录权限
真正卡住人的地方往往不是密码输错,而是 PAM 没报错、vsftpd 不打详细日志、shell 列表和配置文件又分散在不同位置——三者稍一错位,530 就成了黑盒。动手前先确认 getent passwd username 和 getent shells 输出,比反复重置密码有用得多。