Sorun Giderme

MQTT Bağlantı Hataları: Nedenleri ve Çözümleri

MQTT bağlantı hatalarını hızla çözün: zaman aşımı, ECONNREFUSED, TLS hataları, mixed content, CONNACK ve MQTT 5 reason code’ları, client ID döngüleri.

Güncellendi · 8 dk okuma

Bir MQTT bağlantısı dört katmanda başarısız olabilir: ağ (DNS ve TCP), aktarım (TLS veya WebSocket), MQTT el sıkışması (CONNECT / CONNACK) ve canlı oturum (keep-alive ve bağlantı kesilmeleri). Katmanı belirlemek çözümün yarısıdır. Bu rehber, karşılaşmanız muhtemel hata mesajları ve reason code’larıyla birlikte her katmanı tek tek ele alıyor.

Hızlı ön teşhis

BelirtiKatmanEn olası neden
ENOTFOUND / getaddrinfo hatasıDNSHost adında yazım hatası veya host alanına URL şemasının eklenmesi
Takılıyor, sonra zaman aşımına uğruyorAğPortu düşüren bir firewall, yanlış port veya tarayıcıdan TCP portu kullanımı
ECONNREFUSEDAğO host ve portta dinleyen bir şey yok
Sertifika veya el sıkışma hatasıTLSGüvenilmeyen CA, host adı uyuşmazlığı veya düz bir porta TLS ile bağlanma
Bağlandıktan hemen sonra bağlantı kapanıyorMQTTHata kodlu CONNACK — aşağıdaki tablolara bakın
Bağlanıyor, sonra tekrar tekrar kopuyorOturumAynı client ID’nin iki kez kullanılması veya keep-alive yapılandırma hatası

Bağlantı zaman aşımları

Zaman aşımı, paketlerinizin gittiği ama hiçbir şeyin geri gelmediği anlamına gelir. Broker’ın hayır deme fırsatı bile olmamıştır. Sırasıyla şunları kontrol edin:

  1. Port aktarımla eşleşiyor mu? 1883’te mqtt://, 8883’te mqtts://, broker’ın WebSocket portunda wss://. Bkz. MQTT portları.
  2. Ağınız porta izin veriyor mu? Kurumsal ve misafir ağlar genellikle 1883 ve 8883’ü engeller. Doğrulamak için 443 üzerinde wss:// deneyin.
  3. Broker çalışıyor mu? Genel test ortamları haber vermeden yeniden başlar; kendi kurulumunuzu olasılık dışı bırakmak için başka bir broker’ı test edin.
  4. Sunucu firewall’ınız açık mı? Kendi barındırdığınız broker’larda bulut security group’u listener portuna gelen trafiğe izin vermelidir.

ECONNREFUSED

ECONNREFUSED, işletim sisteminden gelen hızlı ve açık bir reddir: host’a erişilebilir, ancak o portta dinleyen bir süreç yoktur. Tipik nedenler; çalışmayan bir broker, yalnızca 127.0.0.1’e bağlanmış bir listener, hiç publish edilmemiş bir container portu (docker run -p 1883:1883) veya broker başka bir container’dayken bir container’ın içinden localhost’a bağlanmaktır.

TLS hataları

  • Kendinden imzalı veya bilinmeyen CA (SELF_SIGNED_CERT_IN_CHAIN, UNABLE_TO_VERIFY_LEAF_SIGNATURE): client’a CA dosyasını verin. Yerel testler dışında doğrulamayı kapatmayın.
  • Host adı uyuşmazlığı (ERR_TLS_CERT_ALTNAME_INVALID): IP adresi veya dahili bir takma ad yerine sertifikadaki adla bağlanın.
  • Wrong version number / packet length too long: düz metin bir porta TLS (örneğin 1883’te mqtts://) ya da TLS portuna düz MQTT konuşuyorsunuz.
  • Süresi dolmuş sertifika: tarihleri openssl s_client -connect host:8883 -servername host ile kontrol edin.

Yalnızca tarayıcıda görülen hatalar: mixed content ve WebSocket path’leri

Tarayıcılar MQTT’yi yalnızca WebSocket üzerinden kullanabilir ve kendi kurallarını ekler. HTTPS üzerinden sunulan bir sayfa ws:// açamaz — tarayıcı daha hiçbir paket gönderilmeden bunu mixed content olarak engeller ve hata yalnızca geliştirici konsolunda görünür. wss:// kullanın. Diğer sık hata eksik path’tir: birçok broker /mqtt bekler ve o olmadan WebSocket upgrade’i 404 ile başarısız olur. Daha fazlası için WebSocket üzerinden MQTT yazısını okuyun.

Çalıştığı bilinen bir wss bağlantısını test edin

MQTT 3.1.1 CONNACK return code’ları

Ağ ve aktarım çalışıyorsa broker CONNECT’e CONNACK ile yanıt verir. MQTT 3.1.1’de bu paket bir baytlık bir return code taşır:

KodAnlamıNe düzeltilmeli
0Connection accepted (bağlantı kabul edildi)Hiçbir şey — bağlısınız
1Unacceptable protocol version (kabul edilemeyen protokol sürümü)Broker istenen sürümü desteklemiyor; MQTT 3.1.1 ile 5 arasında geçiş yapın
2Identifier rejected (tanımlayıcı reddedildi)Client ID geçersiz, çok uzun, izin verilmediği halde boş veya engellenmiş
3Server unavailable (sunucu kullanılamıyor)Broker aşırı yüklü veya bakımda; backoff ile yeniden deneyin
4Bad user name or password (hatalı kullanıcı adı veya parola)Kimlik bilgilerini ve kodlamalarını kontrol edin
5Not authorized (yetkisiz)Hesabın bağlanma izni yok; broker ACL’lerini veya client ID kuralını kontrol edin

Yaygın MQTT 5 reason code’ları

MQTT 5, return code’ların yerine reason code’ları kullanır. 0x80 ve üzerindeki her değer bir hatadır. Aynı kodlar CONNACK içinde veya sunucunun gönderdiği bir DISCONNECT içinde görülebilir:

KodAdTipik neden
0x80Unspecified errorGenel hata; broker log’larını kontrol edin
0x84Unsupported Protocol VersionBroker yalnızca 3.1.1 konuşuyor
0x85Client Identifier not validHatalı biçimli veya izin verilmeyen client ID
0x86Bad User Name or PasswordYanlış kimlik bilgileri
0x87Not authorizedBağlanma izni olmayan geçerli kullanıcı
0x88Server unavailableBroker şu anda bağlantı kabul edemiyor
0x8ABannedClient veya IP, operatör tarafından engellenmiş
0x8CBad authentication methodEnhanced auth yöntemi desteklenmiyor
0x95Packet too largeCONNECT, broker’ın maksimum paket boyutunu aşıyor
0x97Quota exceededHesap bir bağlantı veya kullanım sınırına ulaştı
0x9FConnection rate exceededÇok hızlı yeniden bağlanılıyor; backoff ekleyin

Bir oturum sırasında DISCONNECT paketlerinde iki kod daha görülür: 0x8D (Keep Alive timeout) ve 0x8E (Session taken over). İkisi de aşağıda ele alınıyor. MQTT 5’in neleri değiştirdiğine dair genel tablo için MQTT 5 ve 3.1.1 yazısına bakın.

Client ID devralma döngüleri

Spesifikasyon, aynı client ID ile yeni bir bağlantı geldiğinde broker’ın mevcut client’ın bağlantısını kesmesini şart koşar. İki cihaz — ya da iki tarayıcı sekmesi — bir ID’yi paylaşıyor ve ikisi de otomatik yeniden bağlanıyorsa birkaç saniyede bir sırayla birbirlerini düşürürler. MQTT 5’te kaybeden taraf 0x8E içeren bir DISCONNECT alır; 3.1.1’de ise soket basitçe kapanır.

Keep-alive kaynaklı bağlantı kopmaları

CONNECT içindeki keep-alive değeri broker’a ne sıklıkla trafik bekleyeceğini söyler. Broker bu aralığın bir buçuk katı boyunca hiçbir şey görmezse bağlantıyı kapatır. Client’lar boştayken PINGREQ gönderir, ancak bloklanmış bir event loop, uyuyan bir cihaz veya agresif bir NAT ya da load balancer boşta kalma zaman aşımı yine de bağlantıyı koparabilir. Aralığı ağınızın boşta kalma zaman aşımının altında tutun (60 saniye yaygın bir varsayılandır) ve MQTT client’ına hizmet eden thread’i asla bloklamayın.

Gerçek hatayı log’layın

Çoğu kütüphane, siz dinlemedikçe nedeni gizler. MQTT.js ile:

debug.mjs
import mqtt from 'mqtt';

const client = mqtt.connect('wss://broker.emqx.io:8084/mqtt', {
  protocolVersion: 5,
  clientId: `debug-${Math.random().toString(16).slice(2, 10)}`,
  reconnectPeriod: 5000,
});

client.on('connect', (connack) => console.log('connected', connack.reasonCode ?? 0));
client.on('error', (err) => console.error('error:', err.message, err.code));
client.on('disconnect', (packet) => console.warn('server disconnect, reason', packet.reasonCode));
client.on('close', () => console.warn('socket closed'));

Kontrol listesi

  1. Çalıştığı bilinen bir genel broker’da gidiş-dönüşü online client ile doğrulayın.
  2. Şemayı, portu ve path’i broker’ın belgelenmiş listener’ıyla eşleştirin.
  3. Tahmin etmek yerine CONNACK kodunu veya reason code’u okuyun.
  4. Benzersiz bir client ID kullanın ve backoff ile yeniden bağlanın.
  5. Keep-alive’ı yol üzerindeki tüm boşta kalma zaman aşımlarından kısa tutun.

Eksiksiz bir test prosedürü için MQTT broker nasıl test edilir yazısını izleyin.

Sıkça sorulan sorular

MQTT “connection refused: not authorized” ne anlama gelir?

Broker ağ bağlantısını kabul etmiş ancak client’ı reddetmiştir. MQTT 3.1.1’de bu CONNACK return code 5, MQTT 5’te ise reason code 0x87’dir. Kimlik bilgileri geçerli olabilir, ancak hesabın bağlanmasına veya o client ID’yi kullanmasına izin verilmiyordur.

MQTT client’ım neden sürekli bağlantıyı kesip yeniden bağlanıyor?

En yaygın neden, iki client’ın aynı client ID’yi kullanmasıdır. Broker, bu ID ile her yeni bağlantı geldiğinde eski oturumun bağlantısını keser; ikisi de otomatik yeniden bağlanıyorsa bir döngü içinde birbirlerini düşürürler. Her client’a benzersiz bir ID verin.

MQTT bağlantım neden hata vermek yerine zaman aşımına uğruyor?

Zaman aşımı hiç yanıt gelmediği anlamına gelir; bu da genellikle paketleri sessizce düşüren bir firewall’a, yanlış bir host’a veya tarayıcıdan TCP portunun kullanılmasına işaret eder. Ret ise bir şeyin yanıt verip hayır dediği anlamına gelir.