This section explains how devices can use the MQTT bridge to communicate with Cloud IoT Core. For general information about HTTP and MQTT, see Protocols.

Be sure to refer to the API documentation for full details about each method described in this section. See also the MQTT-related samples.

To publish over the MQTT bridge:

  1. Install an MQTT client on your device.

  2. Download an MQTT server certificate onto your device.

  3. Configure the MQTT client to authenticate the device to Cloud IoT Core.

  4. Initiate a TLS handshake over mqtt.googleapis.com or a long-term support domain.

  5. Publish telemetry events or set the device state.

MQTT server

Cloud IoT Core supports the MQTT protocol by running a managed broker that listens to the port mqtt.googleapis.com:8883. Port 8883 is the standard TCP port reserved with IANA for secure MQTT connections. Connections to this port must use TLS transport, which is supported by open source clients like Eclipse Paho.

If port 8883 is blocked by your firewall, you can also use port 443: mqtt.googleapis.com:443.

Note: If you are using Private Google Access with the default domains, port 8883 is not reachable. Use port 443 instead. If you are using private.googleapis.com or restricted.googleapis.com, including using Private Google Access for on-premises hosts, MQTT is not supported.

Note: The MQTT standard is defined for implementing a full publish/subscribe broker. However, the managed MQTT bridge run by Cloud IoT Core does not support all publish/subscribe operations, such as creating arbitrary topics that devices can use to send messages between them. (Filtering can be accomplished with downstream processes running on Cloud Pub/Sub.) Cloud IoT Core uses a predefined set of topics and specific topic formats.

Quality of Service (QoS)

The MQTT specification describes three Quality of Service (QoS) levels:

Cloud IoT Core does not support QoS 2. Publishing QoS 2 messages closes the connection. Subscribing to a predefined topic with QoS 2 downgrades the QoS level to QoS 1.

QoS 0 and 1 function as follows in Cloud IoT Core:

For device configurations, QoS levels are as follows:

Downloading MQTT server certificates

To use TLS transport, devices must verify Cloud IoT Core server certificates to ensure they're communicating with Cloud IoT Core rather than an impersonator. The following certificate packages support verification:

After downloading Google root CA certificates to your device, you can configure an MQTT client to authenticate the device, connect to the MQTT server, and communicate over the MQTT bridge.

Configuring MQTT clients

MQTT clients authenticate devices by connecting to the MQTT bridge. To configure an MQTT client to authenticate a device:

  1. Set the MQTT client ID to the full device path:

    projects/PROJECT_ID/locations/REGION/registries/REGISTRY_ID/devices/DEVICE_ID
  2. Associate the MQTT client with MQTT server certificates.

  3. Set the MQTT host name to mqtt.googleapis.com or a long-term support domain (if you used the minimal root CA set).

  4. Specify a username. The MQTT bridge ignores the username field, but some MQTT client libraries will not send the password field unless the username field is specified. For best results, supply an arbitrary username like unused or ignored.

  5. Set the password. The password field must contain the JWT.

The following sample shows how to configure the MQTT client to authenticate a device:

C++JavaNode.jsPython

The steps for configuring the client ID and authenticating a device are highlighted below:View on GitHub Feedback

int Publish(char* payload, int payload_size) {  int rc = -1;  MQTTClient client = {0};  MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;  MQTTClient_message pubmsg = MQTTClient_message_initializer;  MQTTClient_deliveryToken token = {0};  MQTTClient_create(&client, opts.address, opts.clientid,                    MQTTCLIENT_PERSISTENCE_NONE, NULL);  conn_opts.keepAliveInterval = 60;  conn_opts.cleansession = 1;  conn_opts.username = k_username;  conn_opts.password = CreateJwt(opts.keypath, opts.projectid, opts.algorithm);  MQTTClient_SSLOptions sslopts = MQTTClient_SSLOptions_initializer;  sslopts.trustStore = opts.rootpath;  sslopts.privateKey = opts.keypath;  conn_opts.ssl = &sslopts;  unsigned long retry_interval_ms = kInitialConnectIntervalMillis;  unsigned long total_retry_time_ms = 0;  while ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {    if (rc == 3) {  // connection refused: server unavailable      usleep(retry_interval_ms * 1000);      total_retry_time_ms += retry_interval_ms;      if (total_retry_time_ms >= kMaxConnectRetryTimeElapsedMillis) {        printf("Failed to connect, maximum retry time exceeded.");        exit(EXIT_FAILURE);      }      retry_interval_ms *= kIntervalMultiplier;      if (retry_interval_ms > kMaxConnectIntervalMillis) {        retry_interval_ms = kMaxConnectIntervalMillis;      }    } else {      printf("Failed to connect, return code %d\n", rc);      exit(EXIT_FAILURE);    }  }

  pubmsg.payload = payload;
  pubmsg.payloadlen = payload_size;
  pubmsg.qos = kQos;
  pubmsg.retained = 0;
  MQTTClient_publishMessage(client, opts.topic, &pubmsg, &token);
  printf(
      "Waiting for up to %lu seconds for publication of %s\n"
      "on topic %s for client with ClientID: %s\n",
      (kTimeout / 1000), opts.payload, opts.topic, opts.clientid);
  rc = MQTTClient_waitForCompletion(client, token, kTimeout);
  printf("Message with delivery token %d delivered\n", token);
  MQTTClient_disconnect(client, 10000);
  MQTTClient_destroy(&client);

  return rc;}

Using a long-term MQTT domain

Long-term support (LTS) domains let you use one TLS configuration for an extended period of time. You can set up an MQTT client once, configure the MQTT client to publish messages through an LTS domain, and then communicate over the MQTT bridge continuously during the supported time frame.

The current active LTS domain is mqtt.2030.ltsapis.goog. This LTS domain is supported through 2030.

To use the LTS domain:

  1. Configure an MQTT client to publish messages through an LTS domain.

    1. Configure the MQTT client to authenticate the device to Cloud IoT Core.

    2. When configuring the device, associate the minimal root CA set's primary and backup certificates with the MQTT client.

  2. Initiate a TLS handshake over mqtt.2030.ltsapis.goog on port 8883 or 443. Use at least the following TLS features.

    Caution: Long term support is only guaranteed if all the TLS requirements below are met by the MQTT client:

For more information on securing MQTT traffic, including messages sent to LTS domains, see Device security recommendations.

Publishing telemetry events

After the device is configured with an MQTT client and connected to the MQTT bridge, it can publish a telemetry event by issuing a PUBLISH message to an MQTT topic in the following format:

/devices/DEVICE_ID/events

The device ID is the string ID of the device specified in the MQTT client ID. The device ID is case sensitive.

Messages published to this MQTT topic are forwarded to the corresponding registry's default telemetry topic. The default telemetry topic is the Cloud Pub/Sub topic specified in the eventNotificationConfigs[i].pubsubTopicName field in the registry resource. If no default Pub/Sub topic exists, published telemetry data will be lost. To publish messages to other Cloud Pub/Sub topics, see Publishing telemetry events to additional Cloud Pub/Sub topics.

The forwarded message data field contains a copy of the message published by the device, and the following message attributes are added to each message in the Cloud Pub/Sub topic:

Attribute

Description

deviceId

The user-defined string identifier for the device, for example, thing1. The device ID must be unique within the registry.

deviceNumId

The server-generated numeric ID of the device. When you create a device, Cloud IoT Core automatically generates the device numeric ID; it's globally unique and not editable.

deviceRegistryLocation

The Google Cloud Platform region of the device registry, for example, us-central1.

deviceRegistryId

The user-defined string identifier for the device registry, for example, registry1.

projectId

The string ID of the cloud project that owns the registry and device.

subFolder

The subfolder can be used as an event category or classification. For MQTT clients, the subfolder is the subtopic after DEVICE_ID/events, which is copied directly. For example, if the client publishes to the MQTT topic /devices/DEVICE_ID/events/alerts, the subfolder is the string alerts.

Note: If you try to publish a device telemetry event without specifying a Cloud Pub/Sub topic for the device's registry, the MQTT connection closes automatically. To verify why the connection closed, get the device details and check the "lastErrorStatus" field in the response. This applies only to telemetry events, not state data.

The following sample shows how to send PUBLISH messages through the MQTT connection:

C++JavaNode.jsPython

This sample uses the Google API Client Library for Python.View on GitHub Feedback

int Publish(char* payload, int payload_size) {
  int rc = -1;
  MQTTClient client = {0};
  MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
  MQTTClient_message pubmsg = MQTTClient_message_initializer;
  MQTTClient_deliveryToken token = {0};

  MQTTClient_create(&client, opts.address, opts.clientid,
                    MQTTCLIENT_PERSISTENCE_NONE, NULL);
  conn_opts.keepAliveInterval = 60;
  conn_opts.cleansession = 1;
  conn_opts.username = k_username;
  conn_opts.password = CreateJwt(opts.keypath, opts.projectid, opts.algorithm);
  MQTTClient_SSLOptions sslopts = MQTTClient_SSLOptions_initializer;

  sslopts.trustStore = opts.rootpath;
  sslopts.privateKey = opts.keypath;
  conn_opts.ssl = &sslopts;

  unsigned long retry_interval_ms = kInitialConnectIntervalMillis;
  unsigned long total_retry_time_ms = 0;
  while ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
    if (rc == 3) {  // connection refused: server unavailable
      usleep(retry_interval_ms * 1000);
      total_retry_time_ms += retry_interval_ms;
      if (total_retry_time_ms >= kMaxConnectRetryTimeElapsedMillis) {
        printf("Failed to connect, maximum retry time exceeded.");
        exit(EXIT_FAILURE);
      }
      retry_interval_ms *= kIntervalMultiplier;
      if (retry_interval_ms > kMaxConnectIntervalMillis) {
        retry_interval_ms = kMaxConnectIntervalMillis;
      }
    } else {
      printf("Failed to connect, return code %d\n", rc);
      exit(EXIT_FAILURE);
    }
  }

  pubmsg.payload = payload;
  pubmsg.payloadlen = payload_size;
  pubmsg.qos = kQos;
  pubmsg.retained = 0;
  MQTTClient_publishMessage(client, opts.topic, &pubmsg, &token);
  printf(
      "Waiting for up to %lu seconds for publication of %s\n"
      "on topic %s for client with ClientID: %s\n",
      (kTimeout / 1000), opts.payload, opts.topic, opts.clientid);
  rc = MQTTClient_waitForCompletion(client, token, kTimeout);
  printf("Message with delivery token %d delivered\n", token);
  MQTTClient_disconnect(client, 10000);
  MQTTClient_destroy(&client);

  return rc;}

Publishing telemetry events to additional Cloud Pub/Sub topics

Devices can publish data to additional Cloud Pub/Sub topics. By default, MQTT messages published to /devices/DEVICE_ID/events are forwarded to the corresponding registry's default telemetry topic. You can specify a subfolder in the MQTT topic to forward data to additional Cloud Pub/Sub topics. The subfolder is the subtopic after /devices/DEVICE_ID/events.

Messages published to a subfolder are forwarded to the Cloud Pub/Sub topic with the same name. The corresponding registry must be configured with the Cloud Pub/Sub topic; otherwise, messages are forwarded to the default Cloud Pub/Sub topic.

Messages are forwarded to the default Cloud Pub/Sub topic instead of the additional Cloud Pub/Sub topic in the following cases:

For example, if the device publishes to the MQTT topic /devices/DEVICE_ID/events/alerts, the subfolder is the string alerts. Messages are forwarded to the additional Cloud Pub/Sub topic if the eventNotificationConfigs[i].subfolderMatches and eventNotificationConfigs[i].pubsubTopicName fields are both set to alerts. Otherwise, messages are forwarded to the default Cloud Pub/Sub topic.

Setting device state

Connected devices can report device state by issuing a PUBLISH message to the following MQTT topic:

/devices/DEVICE_ID/state

To categorize and retrieve state messages, configure the registry with a device state topic. The device state topic is the Cloud Pub/Sub topic specified in the StateNotificationConfig.pubsubTopicName field. If the registry is configured with a device state topic, these messages are forwarded to the matching Cloud Pub/Sub topic on a best-effort basis.

Note: Subfolders are not supported for device state messages. Devices that attempt to publish state messages to an MQTT topic with a subfolder will be automatically disconnected.

For more details on retrieving state messages, see Getting device state.

Limiting MQTT traffic

Cloud IoT Core limits projects that generate excessive load. When devices retry failed operations without waiting, they can trigger limits that affect all devices in the same Google Cloud project.

For retries, you are strongly encouraged to implement a truncated exponential backoff algorithm with introduced jitter.

Keep-alive

When sending the initial MQTT CONNECT message from a client, you can supply an optional "keep-alive" value. This value is a time interval, measured in seconds, during which the broker expects a client to send a message, such as a PUBLISH message. If no message is sent from the client to the broker during the interval, the broker automatically closes the connection. Note that the keep-alive value you specify is multiplied by 1.5, so setting a 10-minute keep-alive actually results in a 15 minute interval.

For more information, see the MQTT specification.

Client settings

Cloud IoT Core does not supply its own default keep-alive value; if you choose to specify a keep-alive interval, you must set it in the client.

For best results, set the client's keep-alive interval to a minimum of 60 seconds. Many open source client libraries, including the Paho MQTT libraries for C, Python, Node.js, and Java, use 60 seconds by default.

Idle time limit

Separate from the keep-alive interval, Cloud IoT Core has its own idle time limit of 20 minutes. Based on this limit, a client connection will automatically be terminated if the client doesn't send any messages for 20 minutes, even if the keep-alive interval is longer. If a keep-alive value isn't supplied, the default idle timeout of 20 minutes still takes effect.

Troubleshooting

If you have trouble connecting, see Troubleshooting.