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

Mosquitto MQTT:Paho Python设置ca_certs为目录触发IsADirectoryError

问题描述

我有一条可正常运行的mosquitto_sub命令:

# this works fine!
mosquitto_sub --capath /etc/ssl/certs/ -u user -P xyz -h hostname.com -p 8883 -t '#'

我编写了对应的Paho Python代码,预期实现相同功能:

import ssl
import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))
    client.subscribe("#")

def on_message(client, userdata, msg):
    print(msg.topic + " " + str(msg.payload))

client = mqtt.Client()
client.username_pw_set("user", "xyz ")
client.tls_set("/etc/ssl/certs/", tls_version=ssl.PROTOCOL_TLSv1_2) # <- line 16

client.on_connect = on_connect
client.on_message = on_message
client.connect("hostname.com", 8883)

client.loop_forever()

但代码运行时抛出异常:

Traceback (most recent call last):
  File "/workspaces/mqtt.py", line 16, in <module>
    client.tls_set("/etc/ssl/certs/", tls_version=ssl.PROTOCOL_TLSv1_2)
  File "/home/vscode/.local/lib/python3.9/site-packages/paho/mqtt/client.py", line 804, in tls_set
    context.load_verify_locations(ca_certs)
IsADirectoryError: [Errno 21] Is a directory

我对此感到困惑,因为Paho MQTT文档说明该参数是“Certificate Authority证书文件的字符串路径”,为何会出现报错?

解决方法

问题核心是mosquitto_sub和Paho Python的参数逻辑差异:

  • mosquitto_sub的--capath接受证书目录,会自动加载目录内所有CA证书
  • Paho Python的tls_set第一个参数ca_certs要求的是单个CA证书文件的路径,传入目录自然触发目录错误

有两种修复方式:

方式一:指定具体CA证书文件

找到系统中合并的CA证书文件(比如多数Linux系统的/etc/ssl/certs/ca-certificates.crt),修改tls_set调用:

client.tls_set("/etc/ssl/certs/ca-certificates.crt", tls_version=ssl.PROTOCOL_TLSv1_2)

方式二:通过SSL上下文加载证书目录

手动创建SSL上下文并指定证书目录,再传给Paho的tls_set_context方法:

import ssl
import paho.mqtt.client as mqtt

# 回调函数保持不变
def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))
    client.subscribe("#")

def on_message(client, userdata, msg):
    print(msg.topic + " " + str(msg.payload))

client = mqtt.Client()
client.username_pw_set("user", "xyz")
# 创建SSL上下文并加载证书目录
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.load_verify_locations(capath="/etc/ssl/certs/")
client.tls_set_context(context)

client.on_connect = on_connect
client.on_message = on_message
client.connect("hostname.com", 8883)

client.loop_forever()

另外注意你代码中username_pw_set的密码末尾多了一个空格("xyz "),建议去掉避免认证失败。

内容的提问来源于stack exchange,提问作者tturbo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 02:57:32