# MQTT 設定

[MQTT](https://mqtt.org/) は、モノのインターネット（IoT）デバイスを接続するための軽量なパブリッシュ／サブスクライブ型メッセージングプロトコルです。EMQX は MQTT 3.1、3.1.1、および 5.0 をサポートしています。

本ページでは、EMQX における MQTT プロトコルの動作設定について、パケット検証や制限、サブスクリプション、遅延パブリッシュ、キープアライブ処理、セッションなどの設定方法を説明します。

## 基本的な MQTT 設定

このセクションでは、パケットサイズ、クライアントIDの長さ、トピックレベル数、QoS（サービス品質）、トピックエイリアス、リテインの設定項目について紹介します。

:::tip

対応する設定項目は EMQX ダッシュボードの **Management** -> **MQTT Settings** -> **General** でも確認できます。ダッシュボードで設定した場合、設定ファイル内の同じ項目より優先されます。  
設定ファイルから MQTT を設定する場合は、`emqx.conf` ではなく `base.hocon` の利用を推奨します。  
`emqx.conf` に設定した場合、ダッシュボードからの変更は一時的なものとなり、EMQX の再起動時に失われるためです。

:::

**設定例:**

```bash
mqtt {
  max_packet_size = 1MB
  max_clientid_len = 65535
  max_topic_levels = 128
  max_qos_allowed = 2
  max_topic_alias = 65535
  retain_available = true
  strict_mode = true
}  
```

各設定項目の説明は以下の通りです。

| **設定項目**             | ダッシュボードUI           | **説明**                                                                                   | **デフォルト値** | **選択可能な値**   |
| ----------------------- | -------------------------- | ------------------------------------------------------------------------------------------ | ---------------- | ------------------ |
| `max_packet_size`       | Max Packet Size            | MQTT パケットは MQTT クライアントと EMQX 間でメッセージを送受信するために使用されます。<br /><br />許可される最大 MQTT パケットサイズを設定します。 | `1MB`            |                    |
| `max_clientid_len`      | Max Client ID Length       | MQTT クライアントIDの最大長を設定します。<br /><br />過度に長いクライアントIDの使用を防止し、問題発生を抑制します。 | `65535`          | `23` - `65535`     |
| `max_topic_levels`      | Max Topic Levels           | MQTT トピックはメッセージの分類・整理に使用されます。<br /><br />トピックの最大レベル数を設定します。 | `128`            | `1` - `35`         |
| `max_qos_allowed`       | Max QoS                   | QoS（サービス品質）レベルはメッセージの信頼性と配信保証のレベルを決定します。<br /><br />許可される最大 QoS レベルを設定します。 |                  |                    |
| `max_topic_alias`       | Max Topic Alias            | トピックエイリアスは、完全なトピック名の代わりに短いエイリアスを使うことで MQTT パケットサイズを削減する方法です。<br /><br />1 セッションで使用可能な最大トピックエイリアス数を設定します。 | `65535`          | `1` - `65535`      |
| `retain_available`      | Retain Available           | リテインメッセージは、トピックに最後にパブリッシュされたメッセージを保持し、新規サブスクライバーが最新メッセージを受信できるようにします。<br /><br />リテイン機能の有効／無効を設定します。 | `true`           | `true`, `false`    |
| `strict_mode`           | Strict Mode                | 受信する MQTT パケットに対して追加のプロトコル準拠チェックを適用するか設定します。チェックに失敗したパケットはクライアント接続を切断します。 | `true`           | `true`, `false`    |

### 厳密な MQTT パケット検証

EMQX 6.3.0 以降、`strict_mode = true` がデフォルトで有効となり、以下のような不正な MQTT パケットは拒否されます。

- 無効な MQTT 固定ヘッダーフラグの組み合わせ
- MQTT 3.1.1 の CONNECT パケットで、Username Flag がないのに Password Flag がある場合
- クライアントID、トピック名、ユーザー名、パスワード、Will トピック、MQTT 5.0 の文字列プロパティなどに無効な UTF-8 文字列（ヌル文字や禁止されている制御文字を含む）
- MQTT プロトコルで非ゼロが要求されるパケット識別子がゼロの場合

不正パケット検出時、EMQX はクライアント接続を切断し、`info` レベルで `frame_parse_error` ログを理由付きで記録します。MQTT 5.0 クライアントには可能な場合、理由コード `0x81`（Malformed Packet）付きの CONNACK または DISCONNECT パケットを送信します。MQTT 3.1 および 3.1.1 クライアントは理由コードなしで切断されます。

既存クライアントがこれらのプロトコル要件に準拠していない場合、一時的に厳密モードの検証を無効化できます。

```bash
mqtt.strict_mode = false
```

特定のレガシークライアントのみで無効化したい場合は、ゾーンを設定し専用リスナーに割り当てます。

```bash
zones.legacy_clients {
  mqtt.strict_mode = false
}

listeners.tcp.legacy {
  bind = "0.0.0.0:1884"
  zone = legacy_clients
}
```

他のリスナー経由のクライアントは引き続き厳密検証を使用します。ゾーンの詳細は [Zone Override](./configuration.md#zone-override) を参照してください。

## サブスクリプション設定

EMQX におけるサブスクリプションとは、クライアントが EMQX 上のトピックをサブスクライブすることを指します。クライアントがトピックをサブスクライブすると、そのトピックにパブリッシュされたメッセージを受信したい意思表示となります。

このセクションでは、共有サブスクリプション、ワイルドカードサブスクリプション、排他サブスクリプションの設定方法を紹介します。

:::tip

対応する設定項目は EMQX ダッシュボードの **Management** -> **MQTT Settings** -> **General** でも確認できます。ダッシュボードで設定した場合、設定ファイル内の同じ項目より優先されます。  
設定ファイルから MQTT を設定する場合は、`emqx.conf` ではなく `base.hocon` の利用を推奨します。  
`emqx.conf` に設定した場合、ダッシュボードからの変更は一時的なものとなり、EMQX の再起動時に失われるためです。

:::

**設定例:**

```bash
mqtt {
	wildcard_subscription = true
  exclusive_subscription = false
  shared_subscription = true
  shared_subscription_strategy  =  round_robin
}
```

各設定項目の説明は以下の通りです。

| **設定項目**                  | ダッシュボードUI               | **説明**                                                                                  | **デフォルト値** | **選択可能な値**                                                                                   |
| ---------------------------- | ------------------------------ | ----------------------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------- |
| `wildcard_subscription`      | Wildcard Subscription Available | ワイルドカードサブスクリプションは、`+` や `#` などのワイルドカードを使い、複数トピックを一括でサブスクライブ可能にします。<br /><br />有効化の設定です。 | `true`           | `true`, `false`                                                                                   |
| `exclusive_subscription`     | Exclusive Subscription          | 排他サブスクリプションは、1つのトピックに対して同時に1つのクライアントのみがサブスクライブ可能にします。<br /><br />有効化の設定です。 | `true`           | `true`, `false`                                                                                   |
| `shared_subscription`        | Shared Subscription Available   | 共有サブスクリプションは、複数のクライアントでトピックのサブスクリプションを共有可能にします。<br /><br />有効化の設定です。 | `true`           | `true`, `false`                                                                                   |
| `shared_subscription_strategy` |                                | 共有サブスクリプションでメッセージを複数クライアントに配信する際の戦略を定義します。<br /><br />`shared_subscription` が `true` の場合のみ必要です。 | `round_robin`    | - `random`（ランダムにサブスクライバーへ配信）<br /><br />- `round_robin`（ラウンドロビン方式で順に配信）<br /><br />- `sticky`（最後に選択されたサブスクライバーに固定、切断まで維持）<br /><br />- `hash`（`clientIds` のハッシュでサブスクライバーを選択） |

## 遅延パブリッシュ設定

遅延パブリッシュ機能は、クライアントがメッセージのパブリッシュを指定時間遅延させることを可能にします。この機能は、特定の時間にメッセージを送信したい場合や、条件を満たしたときに送信したい場合に有用です。

本セクションでは、遅延パブリッシュの有効化方法と遅延メッセージの最大数設定について説明します。

**設定例:**

```bash
delay {
  delayed_publish_enabled = true
  max_delayed_messages = 0
}
```

各設定項目の説明は以下の通りです。

- `delayed_publish_enabled` は遅延パブリッシュ機能の有効化設定です。デフォルトは `true`、選択可能値は `true`、`false`。
- `max_delayed_messages` は許可される遅延メッセージの最大数を設定します。デフォルトは `0`。

## キープアライブ設定

キープアライブは 2 バイトの整数で、秒単位の時間間隔を表します。これは MQTT クライアントと EMQX 間の接続を、データ送信がなくても維持するための仕組みです。クライアントが EMQX に接続する際、CONNECT パケットの可変ヘッダーのキープアライブ値に 0 以外を設定すると、双方でキープアライブ機能が有効になります。詳細は [MQTT キープアライブパラメータとは？](https://www.emqx.com/en/blog/mqtt-keep-alive) を参照してください。

MQTT 5.0 プロトコルに従い、キープアライブが有効なクライアントに対し、サーバーはキープアライブ時間の 1.5 倍の間に MQTT コントロールパケットを受信しなければ、クライアントとのネットワーク接続を切断しなければなりません。  
そこで EMQX は `keepalive_multiplier` という設定を導入し、クライアントのキープアライブタイムアウトを定期的にチェックします。デフォルト値は `1.5` です。

```bash
keepalive_multiplier = 1.5
```

タイムアウト計算式は以下の通りです。

$$
\text{Keep Alive} \times \text{keepalive\_multiplier}
$$

### 動的キープアライブ調整

車載ネットワーク（T-Box）やモバイル IoT のようなシナリオでは、MQTT クライアントは「アクティブ状態」（頻繁な通信）と「スリープ状態」（低消費電力の待機）を切り替えます。単一の固定キープアライブ値では両方のニーズを満たせません。

- 短いキープアライブはアクティブ時の切断検知を高速化しますが、スリープ時はハートビート通信が過剰になりバッテリーを消耗します。
- 長いキープアライブはスリープ時の通信を減らせますが、アクティブ時の切断検知が遅れます。

EMQX は `$SETOPTS/` システムトピック群を通じて、クライアント単位での動的キープアライブ調整をサポートします。クライアント自身がこれらのトピックにパブリッシュしてブローカー側のキープアライブ許容値を更新したり、権限のあるバックエンドサービスが複数クライアントを一括更新したりできます。接続の切断や MQTT 接続の再交渉は不要です。調整はアクティブセッションのメモリ上にのみ適用され、永続化されません。

::: warning リスナーのマウントポイントとの非互換性  
マウントポイントが設定されたリスナー経由のクライアントでは動的キープアライブ調整は機能しません。EMQX はマウントポイントを `$SETOPTS/` プレフィックスの前に適用するため、更新はマウントされたリテラルトピックへの通常メッセージとしてルーティングされ、クライアントにはエラーが通知されません。  
:::

#### 単一クライアント更新：`$SETOPTS/mqtt/keepalive`

クライアントはこのトピックにパブリッシュして自身のブローカー側キープアライブタイムアウトを更新します。EMQX は自動的にパブリッシュ元のセッションからクライアントIDを取得します。

**ペイロード:** 秒単位の非負整数の文字列。

```text
300
```

**有効範囲:** `0`～`65535` 秒。`0` はそのセッションのキープアライブチェックを無効化します。`65535` を超える値は `65535` にクランプされます。クライアントのゾーンに `mqtt.server_keepalive` が設定されている場合、実効値は両者の最小値となります。

**利用例:** 車両が駐車状態に入ると、T-Box クライアントが `$SETOPTS/mqtt/keepalive` に `300` をパブリッシュします。EMQX はブローカー側のキープアライブ許容時間を 300 秒（デフォルトの `1.5×` 倍数で実効 450 秒）に延長し、リモートコマンドの受信を維持します。なおこれはブローカー側のタイムアウト調整のみであり、クライアントの実際の PINGREQ 間隔は変わりません。ハートビート通信を減らすにはクライアント側もキープアライブ間隔を延長する必要があります。

#### 一括更新：`$SETOPTS/mqtt/keepalive-bulk`

バックエンドサービスはこのトピックにパブリッシュして、複数クライアントのキープアライブを一括更新できます。

**ペイロード:** JSON 配列。各要素は以下を含みます。

| フィールド   | 型      | 必須 | 説明                       |
| ------------ | ------- | ---- | -------------------------- |
| `clientid`   | 文字列  | 必須 | 対象 MQTT クライアントID    |
| `keepalive`  | 整数    | 必須 | 新しいキープアライブ間隔（秒、0～65535） |

```json
[
  { "clientid": "tbox-001", "keepalive": 300 },
  { "clientid": "tbox-002", "keepalive": 60 }
]
```

一括更新は非同期で処理され、クラスター対応です。EMQX は対象クライアントをホストするノードを特定し、ノード間 RPC で更新を適用します。内部キューに 10 件以上のリクエストが溜まると追加リクエストは破棄され、警告ログが記録されます。

#### アクセス制御

2 つのトピックは細かい ACL をサポートするために分離されています。

- 認証済みクライアントに `$SETOPTS/mqtt/keepalive` へのパブリッシュを許可し、各デバイスが自身のキープアライブを調整可能にします。
- `$SETOPTS/mqtt/keepalive-bulk` は信頼できるバックエンドサービスのみに制限します。

:::tip
信頼できないクライアントに `$SETOPTS/mqtt/keepalive` へのパブリッシュ権限を与えないでください。キープアライブを `0` に設定されると、そのセッションのキープアライブチェックが完全に無効化され、過度に大きな値は切断されない接続が残り続け、ブローカーリソースを消費する恐れがあります。
:::

両トピックにパブリッシュされたメッセージは EMQX によってインターセプトされ消費され、サブスクライバーには配信されません。

## セッション設定

MQTT におけるセッションとは、クライアントとブローカー間の接続状態を指します。EMQX では、クライアントが接続するとセッションが確立され、トピックのサブスクライブやメッセージの受信、パブリッシュが可能になります。

このセクションではセッションの設定方法を紹介します。

**設定例:**

```bash
mqtt {
    max_subscriptions = infinity
    upgrade_qos = false
    max_inflight = 32
    retry_interval = 30s
    max_awaiting_rel = 100
    await_rel_timeout = 300s
    session_expiry_interval = 2h
    max_session_expiry_interval = infinity
    max_mqueue_len = 1000
    mqueue_priorities = disabled
    mqueue_default_priority = lowest
    mqueue_store_qos0 = true
    force_shutdown {
      max_mailbox_size = 1000
      max_heap_size = 32MB
    }
    force_gc {
      count  =  16000
      bytes  =  16MB
    }
  }
```

各設定項目の説明は以下の通りです。

| **設定項目**                   | ダッシュボードUI           | **説明**                                                                                   | **デフォルト値**                                            | **選択可能な値**                 |
| ----------------------------- | -------------------------- | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | ------------------------------- |
| `max_subscriptions`           | Max Subscriptions          | クライアントが持てる最大サブスクリプション数を設定します。                                | `infinity`                                                  | `1` - `infinity`                |
| `upgrade_qos`                 | Upgrade QoS                | メッセージパブリッシュ後に QoS（サービス品質）レベルをアップグレード可能か設定します。    | `false`（無効）                                             | `true`, `false`                 |
| `max_inflight`                | Max Inflight               | QoS 1 および QoS 2 メッセージの未アック（送信済みだが未確認）最大数を設定します。         | `32`                                                        | `1` - `65535`                   |
| `retry_interval`              | Retry Interval             | QoS 1 または QoS 2 メッセージの再送間隔を設定します。                                    | `30s`<br />単位: 秒                                         | --                              |
| `max_awaiting_rel`            | Max Awaiting PUBREL        | セッション内で `PUBREL` 受信待ちの QoS 2 メッセージ最大数を設定します。<br />上限到達後は新規 QoS 2 `PUBLISH` リクエストをエラーコード `147(0x93)` で拒否します。<br />MQTT の `PUBREL` は QoS 2 メッセージフローでの制御パケットです。 | `100`                                                       | `1` - `infinity`                |
| `await_rel_timeout`           | Max Awaiting PUBREL TIMEOUT | QoS 2 メッセージの `PUBREL` 受信待ちタイムアウト時間を設定します。<br />タイムアウト後、EMQX はパケットIDを解放し警告ログを出力します。<br />注：`PUBREL` 受信の有無にかかわらずメッセージは転送されます。 | `300s`<br />単位: 秒                                         | --                              |
| `session_expiry_interval`     | Session Expiry Interval    | クライアント切断後に EMQX がセッションを保持する期間を設定します。<br />`Clean Session = false` で接続した MQTT 3.1 および 3.1.1 クライアントに適用されます。MQTT 5.0 クライアントは CONNECT プロパティ `Session-Expiry-Interval` で独自に設定します（`max_session_expiry_interval` を参照）。<br />デフォルトのインメモリセッションストアでは、切断されたセッションはこの期間メモリに保持されます。以下の警告も参照してください。 | `2h`                                                        | --                              |
| `max_session_expiry_interval` | Max Session Expiry Interval | MQTT 5.0 クライアントが CONNECT および DISCONNECT パケットの `Session-Expiry-Interval` プロパティで要求できる最大セッション有効期限を制限します。接続時により長い値を要求した場合、EMQX はこの上限にクランプし、CONNACK の同プロパティにクランプ値を返します（MQTT 5.0 仕様 3.2.2.3.2）。DISCONNECT パケットの長い値も同様にクランプされます。MQTT 3.1 および 3.1.1 クライアントには影響ありません。<br />EMQX 6.3.0 以降で利用可能です。 | `infinity`（無制限）                                       | 期間指定<br />または<br />`infinity` |
| `max_mqueue_len`              | Max Message Queue Length   | インメモリセッションのメッセージキュー長制限を設定します。クライアントがオフラインでセッションが残っている場合、インフライトウィンドウが満杯、または送信キューが混雑している場合にメッセージがキューに入ります。キューが上限に達した場合、EMQX は優先的にその優先度の最古の QoS 0 メッセージを削除します。 | `1000`                                                      | `0` - `infinity`                |
| `mqueue_priorities`           | Topic Priorities           | トピック優先度を設定します。ここでの設定は `mqueue_default_priority` の設定を上書きします。 | `disabled` <br />セッションは `mqueue_default_priority` の優先度を使用します。 | `disabled`<br />または<br />`1` - `255` |
| `mqueue_default_priority`     | Default Topic Priorities   | デフォルトのトピック優先度を設定します。                                               | `lowest`                                                    | `highest`， `lowest`            |
| `mqueue_store_qos0`           | Store QoS 0 Message        | クライアントがオフライン、送信キューが混雑、またはインフライトウィンドウが満杯の間に到着した QoS 0 メッセージをインメモリセッションのメッセージキューに保存するか設定します。無効にすると、オフラインや送信キュー混雑時の QoS 0 メッセージは破棄されます。インフライトウィンドウが満杯の場合は即時配信を継続します。 | `true`                                                      | `true`, `false`                |
| `force_shutdown`              | Enable Force Shutdown      | フォースシャットダウン機能の有効化設定です。メールボックスキュー長 (`max_mailbox_size`) またはヒープサイズ (`max_heap_size`) が指定値に達するとクライアント接続処理を強制終了します。 | `true`                                                      | `true`, `false`                |
| `force_shutdown.max_mailbox_size` | Max Mailbox Size           | フォースシャットダウンをトリガーする最大メールボックスキュー長を設定します。             | `1000`                                                      | `1` - `infinity`               |
| `force_shutdown.max_heap_size` | Max Heap Size              | フォースシャットダウンをトリガーする最大ヒープサイズを設定します。                        | `32MB`                                                      | --                            |
| `force_gc`                   | --                         | 指定されたメッセージ数 (`count`) または受信バイト数 (`bytes`) に達した場合に強制ガベージコレクションを有効化します。 | `true`                                                      | `true`, `false`                |
| `force_gc.count`             | --                         | 強制ガベージコレクションをトリガーする受信メッセージ数を設定します。                      | `16000`                                                     | `0` - `infinity`               |
| `force_gc.bytes`             | --                         | 強制ガベージコレクションをトリガーする受信バイト数を設定します。                          | `16MB`<br />単位: `MB`                                      | --                            |

::: warning 切断されたセッションのメモリコスト

デフォルトのインメモリセッションストアでは、有効期限が 0 より大きいセッションはクライアント切断時に削除されません。EMQX はセッション、サブスクリプション、メッセージキューをメモリに保持し、クライアントの再接続または有効期限切れまで維持します。クライアントが再接続しない場合、ノード上の切断セッション数はクライアント切断率と有効期限の積に概ね比例します。

切断後のセッション保持は永続セッションの意図された動作です。ワークロードに応じて十分なメモリを割り当てるか、[durable sessions](../durability/durability_introduction.md) を利用してセッション状態をディスクに保存してください。

:::

:::tip

MQTT 設定をダッシュボードで行う場合は、ダッシュボード左のメニューから **Management** -> **MQTT Settings** をクリックしてください。ダッシュボードで設定した場合、設定ファイル内の同じ項目より優先されます。  
設定ファイルから MQTT を設定する場合は、`emqx.conf` ではなく `base.hocon` の利用を推奨します。  
`emqx.conf` に設定した場合、ダッシュボードからの変更は一時的なものとなり、EMQX の再起動時に失われるためです。

:::

::: tip

EMQX はより詳細なカスタマイズニーズに対応するため、さらに多くの設定項目を提供しています。詳細は [EMQX Enterprise Configuration Manual for Enterprise](https://docs.emqx.com/en/enterprise/v6.3.1/hocon/) を参照してください。

:::
