ESP32 PubSubClient使用自签名证书连接MQTT失败返回状态-2
MQTT连接返回-2故障排查
PubSubClient返回状态码-2代表MQTT_CONNECT_FAILED,即底层TCP/TLS连接根本没有建立成功,你的代码存在三个核心问题:
- 端口与客户端类型不匹配:你使用的
WiFiClientSecure是TLS加密客户端,默认对应MQTT over TLS的服务端口是8883,但你配置的1883是明文MQTT端口,加密客户端往明文端口发TLS握手请求会直接被拒绝。 - 配置顺序错误:你先调用
client.setServer()初始化了PubSubClient的服务端绑定逻辑,之后才给WiFiClientSecure加载CA证书,后续连接时根本读不到你设置的证书,TLS校验直接失败。 - TLS校验规则不匹配:你用IP地址直连broker,但WiFiClientSecure默认开启证书域名校验,你提供的自签名证书的CN、SAN字段没有包含当前连接的IP地址,就算证书加载成功,身份校验也会不通过。
修复方案
根据你是否开启broker的TLS加密,二选一处理:
- 如果broker开了TLS加密(你要用自签名证书连接的场景)
- 把
mqtt_port改成broker实际的TLS监听端口(默认是8883) - 调整配置顺序:先给WiFiClientSecure加载证书、配置校验规则,再给PubSubClient绑定服务端地址
- IP直连场景下临时关闭域名校验(正式环境用域名连接时不要开这个配置,会降低安全性)
- loop函数里必须加
client.loop(),不然连接维持逻辑不会跑
- 把
- 如果broker没开TLS加密
- 直接删掉
WiFiClientSecure相关代码,换成普通WiFiClient,不需要加载任何证书,端口保持1883即可。
- 直接删掉
修正后的参考代码(TLS加密连接版本)
#include <PubSubClient.h> #include <WiFiClientSecure.h> // WiFi配置 const char *ssid = "Wokwi-GUEST"; const char *password = ""; // MQTT配置 const char *mqtt_broker = "152.67.151.213"; const char *topic = "esp32/test"; const char *mqtt_username = "********"; const char *mqtt_password = "********"; const int mqtt_port = 8883; // 替换为你broker的实际TLS端口 const char* root_ca PROGMEM = \ "-----BEGIN CERTIFICATE-----\r\n" \ "MIIDhzCCAm+gAwIBAgIUViQZNJUlRTBYRkTfljNNUN4sjZowDQYJKoZIhvcNAQEL\r\n" \ "BQAwUzELMAkGA1UEBhMCTFYxDTALBgNVBAgMBFJpZ2ExDTALBgNVBAcMBFJpZ2Ex\r\n" \ "CzAJBgNVBAoMAkxVMQwwCgYDVQQLDANTTUkxCzAJBgNVBAMMAkpUMB4XDTIyMDQy\r\n" \ "NzE3MDQ1NVoXDTI3MDQyNzE3MDQ1NVowUzELMAkGA1UEBhMCTFYxDTALBgNVBAgM\r\n" \ "BFJpZ2ExDTALBgNVBAcMBFJpZ2ExCzAJBgNVBAoMAkxVMQwwCgYDVQQLDANTTUkx\r\n" \ "CzAJBgNVBAMMAkpUMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4V/m\r\n" \ "ZNKfBEoqvHHNK4J6TiRtPKRCcGsNgZAOrAK/isJgOiJaZkJ8Ef6s2Moh4RR6GWi9\r\n" \ "QabV9cGAcsa3MbcSzTE6pKlw6EcTmMzX3Wg2xFj4TwUJHXOzPUITvXRPl8GOQS2C\r\n" \ "wlqbOEp7zKnKzfJ/A2nK4CkQZEEJ10AkXzfLiiw0CKHR1KNt23Y8chzfWCU89LBP\r\n" \ "xISCSwBqofhHtN1w//Gh7SyvtGfFRb87yGPpn3ULoes5EmSkqOo3LEmNyz/3rPdB\r\n" \ "cCNZnN6z7vk1alUgMqlsFHT48FAE/xgfBqw35VR2dUAaqIwZTyA9giLssPTizw3C\r\n" \ "REYcIeKCXMWpqa7GRQIDAQABo1MwUTAdBgNVHQ4EFgQU3ezmrWMb7sTUgMJ5JJqR\r\n" \ "uoXF89EwHwYDVR0jBBgwFoAU3ezmrWMb7sTUgMJ5JJqRuoXF89EwDwYDVR0TAQH/\r\n" \ "BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAcUHWtg2ETX5FJNnKjL5wmP+LPhE8\r\n" \ "6VhOzXHdQgO2HTuinzZOoD0kYZ6K06loNBq2+nRcl4SEUQKiSajDcsBrFIy47R1o\r\n" \ "8ztWbM+ALA03FKT6ezWkM75/g6wamyGFoZKQaI71UfW/LVS9AlTPRD4wfcgI6ee0\r\n" \ "ZT6lXLv6GwnA5z1rrVKWBAbR6/6gdAPVYYj9EszTFRqnWLjHDv16zAyP18TBfYFY\r\n" \ "7cddN4dQIUnr/gYNsI1k2pCmB0mQuObxhjq2U3p3siTmEAaNAVF1m+9+DDWy/Aar\r\n" \ "78UuEhtf35C0b6Yj4h7xwNpAmHtikg3HTY0+pciq+bdcPA6buN+eu/eV2Q==\r\n" \ "-----END CERTIFICATE-----\r\n"; WiFiClientSecure espClient; PubSubClient client(espClient); void setup() { Serial.begin(115200); // 连接WiFi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("."); } Serial.println("Connected to the WiFi network"); // 先配置TLS客户端参数 espClient.setCACert(root_ca); espClient.setInsecure(); // 仅IP直连自签名证书场景使用,域名连接时删除该行 // 配置完TLS再绑定MQTT服务器 client.setServer(mqtt_broker, mqtt_port); while (!client.connected()) { String client_id = "wokwi-test"; Serial.printf("Client %s connecting to MQTT broker\n", client_id.c_str()); if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) { Serial.println("MQTT broker connected"); } else { Serial.print("Connect failed, state code: "); Serial.println(client.state()); delay(2000); } } } void loop() { client.loop(); // 必须调用,否则MQTT连接会自动断开 }
额外说明:Wokwi仿真环境默认会同步系统时间,不需要额外编写NTP对时逻辑,不会出现TLS证书时间校验失败的问题。如果换实体硬件测试,需要先联网同步时间再做MQTT连接。
内容的提问来源于stack exchange,提问作者Adrian Pilikser
相关产品推荐
相关产品推荐

