---
title: MQTT
url: https://doc.liz6.com/ja/networking/10-real-time-communication/03-MQTT
locale: ja
area: networking
tags:
- networking
- real-time-communication
date: 2026-06-30
modified: 2026-07-16
description: 低帯域・高レイテンシ・信頼性の低い IoT ネットワーク向けに設計された最も簡潔な pub/sub プロトコル。QoS 0/1/2 で3段階の配信保証を提供し、retained message による状態同期、will message によるオフライン通知を実現。MQTT 5.0 では session expiry や shared subscriptions などのエンタープライズ機能が追加されました。
---

# MQTT

> 低帯域・高レイテンシ・信頼性の低い IoT ネットワーク向けに設計された最も簡潔な pub/sub プロトコル。QoS 0/1/2 で3段階の配信保証を提供し、retained message による状態同期、will message によるオフライン通知を実現。MQTT 5.0 では session expiry や shared subscriptions などのエンタープライズ機能が追加されました。

## 概要

MQTT（Message Queuing Telemetry Transport、1999/2013）は、低帯域・高レイテンシ・信頼性の低い IoT ネットワーク向けに特別に設計された、最も簡潔な pub/sub メッセージプロトコルです。パブリッシャはサブスクライバに直接接続せず、すべてのメッセージは broker（Mosquitto/EMQX）を経由し、topic はワイルドカードによるフィルタリングをサポートします。QoS 0/1/2 は3種類の配信保証を提供し、retained message と will message は状態同期とオフライン通知を実現します。MQTT 5.0（2019）では、session expiry、shared subscriptions などのエンタープライズ機能が追加されました。

## モデル

MQTT は、低帯域・高レイテンシ・信頼性の低いネットワーク（IoT、M2M）向けに設計された、極めてシンプルな pub/sub プロトコルです。すべてのメッセージは central broker（Mosquitto、EMQX）を経由します。

<svg viewBox="0 0 720 300" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="MQTT 发布订阅模型:消息经 Broker 按 topic 过滤分发给匹配的订阅者">
  <defs><marker id="mqtt-pubsub-arrow" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker></defs>
  <rect width="720" height="300" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">パブリッシュ/サブスクライブモデル: Broker 経由で topic に基づきメッセージをフィルタリングして配信</text>

  <rect x="40" y="70" width="150" height="50" rx="8" fill="#4f46e5"/>
  <text x="115" y="90" text-anchor="middle" font-size="12" font-weight="700" fill="#ffffff">温度センサー</text>
  <text x="115" y="108" text-anchor="middle" font-size="10" fill="#e0e7ff">Publisher</text>

  <line x1="190" y1="95" x2="330" y2="95" stroke="#475569" stroke-width="1.7" marker-end="url(#mqtt-pubsub-arrow)"/>
  <text x="260" y="80" text-anchor="middle" font-size="10" fill="#334155">publish "home/bedroom/temp" 23.5</text>

  <rect x="330" y="70" width="150" height="50" rx="8" fill="#0d9488"/>
  <text x="405" y="90" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">Broker</text>
  <text x="405" y="108" text-anchor="middle" font-size="10" fill="#ccfbf1">Mosquitto / EMQX</text>

  <text x="405" y="152" text-anchor="middle" font-size="10.5" fill="#334155">→ 一致するすべてのサブスクライバにプッシュ</text>

  <line x1="405" y1="120" x2="150" y2="188" stroke="#475569" stroke-width="1.5" marker-end="url(#mqtt-pubsub-arrow)"/>
  <line x1="405" y1="120" x2="360" y2="188" stroke="#475569" stroke-width="1.5" marker-end="url(#mqtt-pubsub-arrow)"/>
  <line x1="405" y1="120" x2="570" y2="188" stroke="#475569" stroke-width="1.5" marker-end="url(#mqtt-pubsub-arrow)"/>

  <rect x="60" y="190" width="180" height="48" rx="8" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="150" y="210" text-anchor="middle" font-size="11" font-weight="700" fill="#115e59">"home/bedroom/temp"</text>
  <text x="150" y="228" text-anchor="middle" font-size="9.5" fill="#0f766e">完全一致</text>

  <rect x="270" y="190" width="180" height="48" rx="8" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="360" y="210" text-anchor="middle" font-size="11" font-weight="700" fill="#115e59">"home/+/temp"</text>
  <text x="360" y="228" text-anchor="middle" font-size="9.5" fill="#0f766e">単一レベルワイルドカード +</text>

  <rect x="480" y="190" width="180" height="48" rx="8" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="570" y="210" text-anchor="middle" font-size="11" font-weight="700" fill="#115e59">"home/#"</text>
  <text x="570" y="228" text-anchor="middle" font-size="9.5" fill="#0f766e">複数レベルワイルドカード #（すべてのサブレベルを含む）</text>

  <rect x="40" y="252" width="640" height="40" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="56" y="277" font-size="12" fill="#3730a3">Broker は topic の文字列マッチングのみを行い、メッセージの内容は問いません。+ は単一レベル、# は複数レベルおよびその下のすべてのサブレベルにマッチします。</text>
</svg>

## QoS

<svg viewBox="0 0 720 380" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="MQTT QoS 0/1/2 三级递送保证:握手次数换来的可靠性">
  <defs><marker id="mqtt-qos-arrow" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker></defs>
  <rect width="720" height="380" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">QoS 0/1/2: ハンドシェイク回数で得られる配信保証</text>

  <rect x="30" y="64" width="95" height="40" rx="6" fill="#e2e8f0" stroke="#cbd5e1"/>
  <text x="77" y="81" text-anchor="middle" font-size="12" font-weight="700" fill="#334155">QoS 0</text>
  <text x="77" y="98" text-anchor="middle" font-size="9.5" fill="#64748b">高々1回</text>

  <rect x="135" y="64" width="110" height="40" rx="5" fill="#f1f5f9" stroke="#cbd5e1"/>
  <text x="190" y="81" text-anchor="middle" font-size="10.5" font-weight="700" fill="#334155">PUBLISH qos=0</text>
  <text x="190" y="98" text-anchor="middle" font-size="9" fill="#64748b">Pub→Broker、確認なし</text>

  <line x1="245" y1="84" x2="263" y2="84" stroke="#475569" stroke-width="1.6" marker-end="url(#mqtt-qos-arrow)"/>

  <rect x="263" y="64" width="110" height="40" rx="5" fill="#f1f5f9" stroke="#cbd5e1"/>
  <text x="318" y="81" text-anchor="middle" font-size="10.5" font-weight="700" fill="#334155">PUBLISH qos=0</text>
  <text x="318" y="98" text-anchor="middle" font-size="9" fill="#64748b">Broker→Sub、確認なし</text>

  <line x1="373" y1="84" x2="391" y2="84" stroke="#475569" stroke-width="1.6" marker-end="url(#mqtt-qos-arrow)"/>

  <rect x="391" y="64" width="140" height="40" rx="6" fill="#e2e8f0" stroke="#cbd5e1"/>
  <text x="461" y="81" text-anchor="middle" font-size="11" font-weight="700" fill="#334155">fire and forget</text>
  <text x="461" y="98" text-anchor="middle" font-size="9" fill="#64748b">確認なし ・ リトライなし</text>

  <rect x="30" y="140" width="95" height="40" rx="6" fill="#ffedd5" stroke="#f97316"/>
  <text x="77" y="157" text-anchor="middle" font-size="12" font-weight="700" fill="#9a3412">QoS 1</text>
  <text x="77" y="174" text-anchor="middle" font-size="9.5" fill="#c2410c">少なくとも1回</text>

  <rect x="135" y="140" width="150" height="40" rx="5" fill="#ffedd5" stroke="#f97316"/>
  <text x="210" y="157" text-anchor="middle" font-size="10.5" font-weight="700" fill="#9a3412">PUBLISH qos=1,id=N</text>
  <text x="210" y="174" text-anchor="middle" font-size="9" fill="#c2410c">Publisher→Broker</text>

  <line x1="285" y1="160" x2="303" y2="160" stroke="#475569" stroke-width="1.6" marker-end="url(#mqtt-qos-arrow)"/>

  <rect x="303" y="140" width="150" height="40" rx="5" fill="#ffedd5" stroke="#f97316"/>
  <text x="378" y="157" text-anchor="middle" font-size="10.5" font-weight="700" fill="#9a3412">PUBACK id=N</text>
  <text x="378" y="174" text-anchor="middle" font-size="9" fill="#c2410c">Broker→Publisher ・ 確認</text>

  <line x1="453" y1="160" x2="471" y2="160" stroke="#475569" stroke-width="1.6" marker-end="url(#mqtt-qos-arrow)"/>

  <rect x="471" y="140" width="130" height="40" rx="6" fill="#ffedd5" stroke="#f97316"/>
  <text x="536" y="157" text-anchor="middle" font-size="11" font-weight="700" fill="#9a3412">重複の可能性あり</text>
  <text x="536" y="174" text-anchor="middle" font-size="9" fill="#c2410c">retransmission</text>

  <rect x="30" y="216" width="95" height="40" rx="6" fill="#dcfce7" stroke="#4ade80"/>
  <text x="77" y="233" text-anchor="middle" font-size="12" font-weight="700" fill="#166534">QoS 2</text>
  <text x="77" y="250" text-anchor="middle" font-size="9.5" fill="#15803d">ちょうど1回</text>

  <rect x="135" y="216" width="90" height="40" rx="5" fill="#dcfce7" stroke="#4ade80"/>
  <text x="180" y="233" text-anchor="middle" font-size="9.5" font-weight="700" fill="#166534">①PUBLISH</text>
  <text x="180" y="250" text-anchor="middle" font-size="8.5" fill="#15803d">Pub→Broker</text>

  <line x1="225" y1="236" x2="239" y2="236" stroke="#475569" stroke-width="1.5" marker-end="url(#mqtt-qos-arrow)"/>

  <rect x="239" y="216" width="90" height="40" rx="5" fill="#dcfce7" stroke="#4ade80"/>
  <text x="284" y="233" text-anchor="middle" font-size="9.5" font-weight="700" fill="#166534">②PUBREC</text>
  <text x="284" y="250" text-anchor="middle" font-size="8.5" fill="#15803d">Broker→Pub</text>

  <line x1="329" y1="236" x2="343" y2="236" stroke="#475569" stroke-width="1.5" marker-end="url(#mqtt-qos-arrow)"/>

  <rect x="343" y="216" width="90" height="40" rx="5" fill="#dcfce7" stroke="#4ade80"/>
  <text x="388" y="233" text-anchor="middle" font-size="9.5" font-weight="700" fill="#166534">③PUBREL</text>
  <text x="388" y="250" text-anchor="middle" font-size="8.5" fill="#15803d">Pub→Broker</text>

  <line x1="433" y1="236" x2="447" y2="236" stroke="#475569" stroke-width="1.5" marker-end="url(#mqtt-qos-arrow)"/>

  <rect x="447" y="216" width="90" height="40" rx="5" fill="#dcfce7" stroke="#4ade80"/>
  <text x="492" y="233" text-anchor="middle" font-size="9.5" font-weight="700" fill="#166534">④PUBCOMP</text>
  <text x="492" y="250" text-anchor="middle" font-size="8.5" fill="#15803d">Broker→Pub</text>

  <line x1="537" y1="236" x2="551" y2="236" stroke="#475569" stroke-width="1.5" marker-end="url(#mqtt-qos-arrow)"/>

  <rect x="551" y="216" width="130" height="40" rx="6" fill="#dcfce7" stroke="#4ade80"/>
  <text x="616" y="233" text-anchor="middle" font-size="10.5" font-weight="700" fill="#166534">重複も欠落もない</text>
  <text x="616" y="250" text-anchor="middle" font-size="8.5" fill="#15803d">4回のハンドシェイク確認</text>

  <rect x="30" y="290" width="660" height="68" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="46" y="315" font-size="12.5" fill="#3730a3">QoS の数字が大きいほどハンドシェイク回数が増え、配信の信頼性は高まりますが、レイテンシと帯域幅のオーバーヘッドも増加します。</text>
  <text x="46" y="337" font-size="12.5" fill="#3730a3">MQTT では、グローバルな一律の指定ではなく、メッセージごとに選択権が与えられます。</text>
</svg>

## MQTT CONNECT/CONNACK

```
CONNECT:
  protocol_name: "MQTT" (v3.1.1) または "MQIsdp" (v3.1)
  protocol_level: 4 (v3.1.1) または 5 (v5.0)
  flags: clean_session, will_flag, will_qos, will_retain, password_flag, username_flag
  keep_alive: 秒 (publisher は keep_alive 秒以内に PINGREQ を送信する必要があります)
  client_id: 一意の ID (空の場合 → broker が割り当て、v5.0 のみ)
  [will_topic, will_message] ← will_flag=1 の場合
  [username, password]

CONNACK:
  session_present: 0 (新しいセッション), 1 (既存のセッションの再開)
  return_code: 0=成功, 1-5=失敗理由
```

## Will Message

クライアントは接続時に宣言します。「もし私が異常に切断された場合、このメッセージを broker が送信してください」: CONNECT will_topic + will_message + will_retain。クライアントが異常切断（TCP close または keepalive タイムアウト）すると、broker は will message をパブリッシュします。

## MQTT 5.0 の改善点

1. **Session expiry**: 切断後にセッションを保持する期間（キュー内の QoS 1/2 メッセージは継続）
2. **Message expiry**: 単一メッセージの TTL
3. **Shared subscriptions**: 複数のサブスクライバによる負荷分散（ラウンドロビン）
4. **Reason codes**: すべての ACK メッセージに具体的な理由を含む
5. **Topic aliases**: 1/2バイトのエイリアスで完全な topic を置き換え → 帯域幅を節約

## 参考

- **broker**: Eclipse Mosquitto (C), EMQX (Erlang), VerneMQ
- **ツール**: `mosquitto_pub -h broker -t topic -m "hello"`, MQTT Explorer

*Keywords: MQTT, pub/sub, QoS, retained, will, Mosquitto, IoT, topic filter*
