プロトコル

MQTTとは?Pub/Subの仕組み・QoS・MQTT 5.0の実装からHTTPとの使い分けまで実装者向けに解説

工場の設備数百台から1秒おきに温度を集める、車両の位置を移動体通信で送り続ける、遠隔地のセンサーを電池で1年動かす。こうした要件を渡されたとき、実装者が最初に候補へ挙げるのがMQTTです。ところが着手すると、QoSをどれにするか、切断をどう検知するかで手が止まります。本記事では制御パケットの粒度で通信の中身を分解し、MQTT 5.0の機能、Pythonでの最小実装、採否の判断までを2026年7月時点の一次情報で整理しました。

まとめ:MQTTの仕組みと採用判断の結論

MQTTは、帯域と電力が限られた環境でメッセージをやり取りするために設計された軽量なPub/Sub型の通信プロトコルです。仕様はOASISが管理し、3.1.1が2014年10月29日、5.0が2019年3月7日にOASIS Standardとして承認されました。動作はTCPの上で、既定ポートは平文が1883番、TLSが8883番です。

軽さの正体は固定ヘッダにあります。制御パケットは2バイトの固定ヘッダから始まる構造で、HTTPのように毎回ヘッダ行を送りません。構造上の特徴は、送信側と受信側が互いを知らない点にあります。送信側は「トピック」という文字列を宛先にして発行し、受信側はそのトピックを購読する。仲介するのがブローカーで、機器の追加や停止が相手側の実装に波及しません。配信の確からしさはQoS 0・1・2で選び、切断時の遺言メッセージ(LWT)と最新値の保持(Retain)で状態を表現します。

新規開発なら3.1.1ではなく5.0を選んでください。採否の軸は「多数の機器から少量のデータを継続的に集めるか」と「サーバーから機器へ届ける必要があるか」の2つ。どちらも当てはまらないならHTTPのAPIで十分です。

MQTTとは何か|IoT向けに設計された軽量なPub/Subプロトコル

2バイトの固定ヘッダが生む軽さと、HTTPの往復モデルとの構造差

HTTPで機器のデータを集める場合、機器は一定間隔でサーバーへリクエストを投げます。1回の送信ごとにTCP接続の確立、TLSハンドシェイク、リクエスト行とヘッダ群、レスポンスが発生する構造。実データが数十バイトの温度値でも、周辺の手続きが通信量の大半を占めます。

MQTTは接続を張りっぱなしにして、その上にメッセージを流す形です。接続確立の費用は最初の1回だけで、以降のPUBLISHは固定ヘッダ+トピック名+ペイロードという構成。電池駆動の機器では無線モジュールが起きている時間がそのまま寿命に響くため、この差が仕様選定の理由になります。接続が双方向である点も違いで、サーバー側から機器へ指示を届ける経路を別途作らずに済みます。

Pub/Subモデル|ブローカーが送信側と受信側を疎結合にする

MQTTの通信には必ずブローカーが挟まります。機器(パブリッシャー)が発行し、ブローカーが購読者(サブスクライバー)へ配る形で、両端は相手のIPアドレスも起動状態も知りません。

設計上の意味は疎結合です。センサーを100台足しても受け取る側のコードは変わらず、分析基盤とアラート通知の2系統で使いたくなったら、同じトピックをもう1つのクライアントが購読するだけで済む。受け手が落ちていても、ブローカーが受理した時点で送信側の責務は終わります。ブローカーそのものの役割、主要製品の比較、Mosquittoでの構築手順はMQTTブローカーとは?仕組み・主要ブローカー比較・構築手順で扱っているため、本記事はプロトコル側の動作に絞ります。

トピックの階層設計とワイルドカード(+・#)による購読の絞り込み

トピックはスラッシュ区切りの文字列で、URLのパスに似た階層を作ります。factory/line1/machine3/temperatureのように、粗い分類から細かい対象へ並べるのが基本形です。

購読側は2種類のワイルドカードを使えます。+は1階層だけを任意にし、#は以降の全階層に一致して末尾にのみ置けます。

記法 一致する範囲 使いどころ
完全一致 その1トピックのみ 個別機器の制御指示
+ 1階層を任意にする 同種の機器を横断
# 以降の全階層 監視・ログ収集

設計で効くのは、後から絞り込みたくなる粒度を先頭側に置くことです。測定項目を先頭に置くと、工場単位の権限設定やワイルドカード購読が組み立てにくくなります。

接続と配信の仕組み|15種類の制御パケットで何が起きているか

CONNECTからCONNACKまでの往復と、接続時に決まる項目

MQTT 5.0の制御パケットは15種類です。接続のCONNECT・CONNACK、発行のPUBLISHと確認応答群(PUBACK・PUBREC・PUBREL・PUBCOMP)、購読のSUBSCRIBE・SUBACK・UNSUBSCRIBE・UNSUBACK、疎通確認のPINGREQ・PINGRESP、切断のDISCONNECT、拡張認証のAUTH。3.1.1には最後のAUTHがなく14種類でした。

クライアントはTCP接続後、最初にCONNECTを送ります。渡すのはクライアント識別子(Client Identifier)、キープアライブ間隔、セッションの扱い、資格情報、LWTの内容。ブローカーはCONNACKで受理か拒否かを返します。

実装で最初に踏む地雷がクライアント識別子の重複です。同じ識別子で2台目が接続すると、仕様上ブローカーは先の接続を切ります。固定文字列をファームウェアへ焼き込むと、2台目を現場へ置いた瞬間に両方が接続と切断を繰り返す。識別子はシリアル番号など一意になる値から組み立ててください。

キープアライブとハーフオープン|機器の切断はすぐには分からない

MQTTはTCPの上で動きますが、TCPの切断検知は当てになりません。無線の圏外や電源断ではFINもRSTも飛ばず、接続が「開いたまま死ぬ」状態(ハーフオープン)になるためです。ブローカー側は生きていると認識し続け、送ったメッセージは届きません。

これを埋めるのがキープアライブです。クライアントはCONNECTで間隔を秒で宣言し、その間に送るものがなければPINGREQを送る。ブローカーは宣言された間隔の1.5倍を超えて何も受け取らなければ、接続を切断してLWTを配信します。設計で意識すべきは検知までの遅れです。キープアライブを60秒にすれば、機器が落ちてからLWTが飛ぶまで最大90秒かかります。異常をすぐ知りたい設備では短く、電池駆動で通信を減らしたい機器では長く。監視要件と電力要件のどちらを優先するかを機器の種類ごとに決めてください。

セッション状態|Clean Startとセッション有効期限の設計

MQTTは接続が切れてもセッション状態を残せます。残るのは購読の一覧と未完了のQoS 1・2のメッセージで、電波が途切れた機器は再接続後も購読し直さずに済む。3.1.1ではClean Sessionフラグの真偽だけで、falseなら「無期限に残す」意味でした。5.0はここを2つに分け、Clean Startが「接続時に既存のセッションを捨てるか」を、Session Expiry Intervalが「切断後どれだけ残すか」を秒で決めます。

この分離は運用で効きます。無期限に残す設定のまま機器を入れ替えると、誰も接続しないセッションと未配信メッセージがブローカーへ溜まり続けるためです。移動体通信で数分の切断が起きる機器なら有効期限を数時間に、常時接続の設備なら短めに設定してください。

QoS・Retain・LWT|配信の性質を決める3つの仕掛け

QoSは到達保証の水準で、0が最大1回(届かないことがある)、1が最低1回(重複することがある)、2が正確に1回です。数字が上がるほど往復が増え、遅延と負荷も増えます。高頻度のセンサー値は0、指示や課金のイベントは1、二重処理が許されない操作は2が実務の基準。発行側と購読側でQoSは別々に決まり、実効的な水準は小さいほうに引きずられます。送達手順やDUPフラグはMQTT QoSとは?0・1・2の違いと選び方で扱っています。

Retainは、ブローカーがトピックごとに最後の1件を保持し、新しく購読した相手へ即座に渡す仕組みです。監視画面を開いた瞬間に現在値が出るのはこの働きによります。イベント通知のトピックでRetainを立てると過去のイベントが再生されるため、状態を表すトピックにだけ使ってください。

LWT(Last Will and Testament)は、接続が異常終了したときにブローカーが代理で発行するメッセージです。CONNECTの時点でトピックと本文を預けておき、キープアライブ切れやTCP切断で配信されます。オンライン状態のトピックにRetain付きで「online」を発行し、LWTに「offline」を仕込む形が定番です。

MQTT 3.1.1と5.0の違い|実装判断が変わる6つの追加機能

理由コードとユーザープロパティで障害の切り分けがどう変わるか

3.1.1では接続や購読が失敗しても返る情報が乏しく、原因の切り分けは推測とログ照合に頼っていました。5.0はCONNACKやSUBACKなどに理由コードを載せ、認証失敗、認可されていないトピック、パケットサイズ超過、サーバー都合の切断といった区別が受け取れます。

ユーザープロパティは、任意のキーと値の組をパケットに添える仕組みです。HTTPのカスタムヘッダに相当し、ファームウェア版数や測定時刻をペイロードの外側へ置けます。受け手は本体を解析せずに振り分けを判断できるでしょう。

共有購読($share)で購読側をコンテナごと水平に増やす設計

MQTTの既定動作では、同じトピックを購読する全員に同じメッセージが配られます。処理側を2台に増やしても重複して処理するだけで、負荷は分散しません。3.1.1では機器を担当ごとに割り振るなどアプリ側の工夫が必要でした。

5.0の共有購読は、$share/<グループ名>/<トピック> の形で購読すると、同じグループの購読者のうち1つだけへ配信します。処理側をコンテナで水平に増やせば、そのまま処理能力が増える構造。1台落ちても残りが受け持つため、大量の機器を扱う収集基盤ではこの1機能だけでも5.0を選ぶ理由になります。

Request/Responseとフロー制御、トピックエイリアス

Pub/Subは本来一方向ですが、機器へ指示を出して結果を受け取りたい場面は避けられません。5.0はResponse TopicとCorrelation Dataをプロパティとして定め、要求側が返信先トピックと照合用のIDを添えて送れるようになりました。3.1.1では各社が独自の命名規約で代替していた部分です。

フロー制御はReceive Maximumで指定します。応答待ちのメッセージを同時に何件まで抱えるかを両者が宣言し、それを超える送信を止める仕掛け。処理が遅い購読者へ送り込み続ける事故を防げます。

トピックエイリアスは、長いトピック名を数値に置き換えて送る機能です。深い階層の文字列を毎回送らずに済むため、帯域課金の移動体通信では費用に直結します。

MQTT 3.1.1から5.0へ移行するときの現実的な手順と順序

MQTT 5.0は3.1.1と互換ではなく、パケットの構造にプロパティ領域が加わっています。ただしブローカー側は両方の版を受け付ける実装が主流で、機器を一斉に入れ替える必要はありません。

順序 作業 確認する点
1 ブローカーを5.0対応版へ 3.1.1接続が維持されるか
2 サーバー側クライアントを5.0へ 理由コードのログ出力
3 共有購読へ切り替え 重複処理が消えたか
4 機器を順次5.0へ セッション有効期限の値

先にサーバー側を5.0へ上げるのは、機器のファームウェア更新が最も時間と費用を要するためです。共有購読やセッション有効期限は機器が3.1.1のままでも効果が出ます。

MQTTとHTTP・WebSocket・AMQPの違いと選び分け

MQTT・HTTP・WebSocket・AMQPを一枚の表で比べる

項目 MQTT HTTP WebSocket AMQP
通信モデル Pub/Sub 要求と応答 双方向ストリーム キューとルーティング
仲介役 ブローカー必須 不要 不要 ブローカー必須
ヘッダ量 固定2バイトから 数百バイト規模 数バイトから MQTTより大きい
到達保証 QoS 0/1/2 アプリ側で実装 アプリ側で実装 ack・トランザクション
主な用途 機器のデータ収集 API・画面表示 チャット・通知 基幹の非同期連携

選び分けの起点は「1対多になるか」です。1台のサーバーと1つのクライアントが会話するだけならWebSocketで足り、ブローカーの運用は負担にしかなりません。多対多で片方の増減が波及しない構造が要るならMQTT、順序保証や複雑なルーティングを伴う基幹連携ならAMQPが向きます。

MQTT over WebSocketという構成と、WebSocketとの住み分け

ブラウザからMQTTへ直接繋ぐことはできません。生のTCPソケットを開けないためです。そこで使うのがMQTT over WebSocketで、ブローカー側は8083番や8084番(TLS)といった別ポートで待ち受ける実装が一般的です。

この構成の利点は、企業のプロキシやファイアウォールを通りやすい点にあります。1883番を塞ぐ環境でも、HTTPからのアップグレードで確立するWebSocketなら通ることが多い。ブラウザで監視画面を作る場合の標準的な選択です。WebSocket側のハンドシェイクやフレーム構造はWebSocketとは?仕組み・実装・運用の判断で扱っています。

実装|Python(paho-mqtt 2.x系)とTLS・認証の要点

publishとsubscribeを1ファイルで動かす最小コード

Pythonの標準的なクライアントはEclipse Paho(PyPI上は paho-mqtt)で、2026年7月時点の配布は2.1系です。2.0系でコンストラクタの仕様が変わり、コールバックAPIの版を明示する引数が必須になりました。既存のサンプルは1.x系のまま書かれたものが多く、そのまま貼ると例外になります。

import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, reason_code, properties):
    print(f"connected: {reason_code}")
    client.subscribe("factory/line1/+/temperature", qos=1)

def on_message(client, userdata, msg):
    print(msg.topic, msg.payload.decode())

client = mqtt.Client(
    mqtt.CallbackAPIVersion.VERSION2,
    client_id="collector-01",
    protocol=mqtt.MQTTv5,
)
client.username_pw_set("collector", "********")
client.will_set("factory/line1/collector-01/status", "offline", qos=1, retain=True)
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.example.jp", 1883, keepalive=60)
client.loop_forever()

押さえる点は4つです。第1引数のCallbackAPIVersion.VERSION2が2.x系での必須指定、protocol=mqtt.MQTTv5が5.0の明示、will_set()が接続前に呼ぶLWTの登録、loop_forever()が再接続とキープアライブを内部で回す役割。発行側はclient.publish()の1行で足ります。

TLSと認証|8883番ポートとクライアント証明書による3段構え

1883番は平文で、ユーザー名とパスワードもそのまま流れます。検証環境を超えるなら8883番のTLSへ切り替えてください。paho-mqttではclient.tls_set()にCA証明書のパスを渡して接続前に呼び、ポートを変えるだけです。

機器の認証は3段構えです。第1にトランスポート側のTLS、第2に資格情報またはクライアント証明書、第3にトピック単位のアクセス制御(ACL)。3つ目を省くと、1台の資格情報が漏れただけで全トピックの購読と発行を許すことになります。

ブローカーを自前で構築するか、マネージドサービスへ委ねるかの判断

ブローカーの選択肢は、Mosquitto(2026年7月時点の配布は2.1系)やEMQXを自前で立てる形と、クラウドのマネージドサービスを使う形に分かれます。判断材料は接続台数と可用性の要件、運用体制。数十台規模の社内利用なら単一のMosquittoで足り、数千台規模や停止が業務停止に直結する用途ならクラスタ構成かマネージドが現実的でしょう。AWS上に構築するなら、証明書管理やルールエンジンによる転送まで含めてAWS IoT Coreの機能・料金・MQTT接続方法を確認してください。マネージドは接続数とメッセージ数の従量課金、自前構築はサーバー費用と運用工数の固定費という差になります。

MQTTを採用してよい3条件と、見送るべき3つの場面の判断軸

MQTTを採用してよい3つの条件と、それが実際に効いてくる場面

第1に、送信側が多数で、1件あたりのデータが小さく、送信が継続的であること。数十台以上の機器が数秒から数分おきに数十バイトを送る形が典型で、HTTPのヘッダ量とTCP再確立の費用が無視できなくなります。

第2に、サーバー側から機器へ届ける必要があること。ファームウェア更新の指示、設定値の変更、遠隔での停止操作。機器がNAT配下や移動体通信網にいても、機器から張った接続の上を指示が流れます。

第3に、データの受け手が増減する見込みがあること。後から分析基盤やアラート通知が加わるなら、受け手の追加が購読1つで済む構造が効いてきます。受け手が1つで固定なら、この利点は発生しません。

MQTTを見送るべき3つの場面と、そのときに選ぶべき代替の手段

第1に、1回の要求に1つの答えを返すだけで済む場面。在庫を問い合わせる、帳票を生成するといった処理はHTTPのAPIが素直で、ブローカーという単一障害点を増やす理由がありません。

第2に、大きなファイルを運ぶ場面。MQTTのペイロードは仕様上256MBまで扱えますが、実装側で上限が設けられブローカーのメモリを圧迫します。画像や動画はオブジェクトストレージへ置き、MQTTではURLだけを流してください。

第3に、厳密な順序保証やトランザクションが要る場面。MQTTはトピック内の順序を扱いますが、複数トピックにまたがる順序や失敗時に巻き戻す仕組みは持ちません。基幹の非同期連携でこれらが要るなら、AMQPを話すメッセージ基盤の検討になります。

トピック設計とACLで運用後に効いてくる3つの失敗パターン例

運用に入ってから直しにくいのがトピック設計です。ファームウェアへ焼き込んだトピックは、変更に現地作業を伴います。よくある失敗の1つ目は、トピックへ可変の値を入れずペイロードのJSONだけで機器を区別する設計で、ACLで機器ごとの権限が切れなくなります。

2つ目は階層が浅すぎてワイルドカードで絞れない設計、3つ目は状態のトピックとイベントのトピックを同じ階層に混ぜてRetainが噛み合わなくなる形。指針は明快で、権限を切りたい単位を上位階層に置き、状態側はRetain付き、イベント側はRetainなしと決めておけば購読側も迷いません。

MQTT収集基盤の開発を外部へ委ねるとき見積書で確かめる5項目

MQTTを含む収集基盤を外部へ委託する場合、見積書で確かめる項目は次の5つです。第1にブローカーの構成(単一かクラスタか、自前かマネージドか)と可用性の水準、第2にトピック設計とACLが成果物に含まれるか、第3に証明書や資格情報の発行と失効の運用を含むか、第4にQoSとセッション有効期限の設定根拠が示されるか、第5に収集したデータを既存システムへ渡す部分の範囲です。

実務で費用が膨らむのは5つ目でしょう。MQTTで集めるところまでは短期間で組めても、そのデータを基幹システムやBIへ流し込む部分に工数の大半がかかります。一創では収集基盤と既存システムを繋ぐ部分をAPI開発・システム連携として請けています。

よくある質問

MQTTとHTTPはどちらを使えばよいですか?

多数の機器から小さなデータを継続的に集める、あるいはサーバーから機器へ指示を届ける要件ならMQTTです。1回の要求に1つの答えを返す形で済むならHTTPのAPIを選んでください。データ収集はMQTT、管理画面はHTTPという分担も一般的です。

MQTTはブローカーなしで使えますか?

使えません。MQTTはブローカーを介する前提の仕様で、機器同士が直接やり取りする形は定義されていないためです。ブローカーを持ちたくないなら別のプロトコルの検討になります。

MQTT 5.0と3.1.1のどちらを選ぶべきですか?

新規開発なら5.0です。理由コードによる障害調査、共有購読、セッション有効期限の明示は、いずれも運用に入ってから効きます。既存機器が3.1.1でも主要なブローカーは両方の版を受け付けるため、サーバー側から先に移行できます。

MQTTのセキュリティはどう確保しますか?

8883番でのTLS、機器ごとの資格情報または証明書、トピック単位のACLの3つを揃えます。3つ目を省くと、資格情報が1つ漏れただけで全トピックが読み書きできる状態になる。パブリックブローカーは検証用途に限り、本番では使わないでください。

機器が切断したことをどうやって検知しますか?

LWTとキープアライブの組み合わせです。接続時に「offline」を本文とするLWTを登録し、接続後に同じトピックへRetain付きで「online」を発行します。キープアライブ間隔の1.5倍を超えて無通信になるとLWTが配信されるため、購読側は1トピックを見るだけで判断できます。

関連記事

資料請求

RELATED POSTS 関連記事