Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/gatling/gatling.io-doc/llms.txt

Use this file to discover all available pages before exploring further.

Gatling’s MQTT support allows you to load test IoT message brokers and pub/sub systems using the MQTT protocol versions 3.1, 3.1.1, and 5. You can model realistic device behavior—connecting clients, subscribing to topics, publishing telemetry payloads, and verifying responses—all at high concurrency. This is particularly useful for validating IoT platforms, smart-home backends, and telemetry pipelines under realistic load.
The Gatling MQTT component is distributed under the Gatling Enterprise Component License. When run with the Community Edition, tests are limited to 5 users and 5 minutes. Unlimited usage requires Gatling Enterprise.
MQTT 3.1, 3.1.1, and 5 are supported. Some features introduced in MQTT 5 may not yet be available.

Project Setup

The Gatling MQTT plugin is not included by default. Add it alongside your standard Gatling dependencies.
1

Add the MQTT dependency

<dependency>
  <groupId>io.gatling</groupId>
  <artifactId>gatling-mqtt</artifactId>
  <scope>test</scope>
</dependency>
2

Add imports

import io.gatling.javaapi.mqtt.*;
import static io.gatling.javaapi.mqtt.MqttDsl.*;
A demo project is available for Java (Maven/Gradle), Kotlin (Maven/Gradle), Scala (sbt), JavaScript, and TypeScript.

MQTT Protocol Configuration

Use the mqtt object to build a protocol configuration that is attached to your scenario via protocols(...).
Java
MqttProtocolBuilder mqttProtocol = mqtt
  .broker("localhost", 1883)
  .useTls(false)
  .clientId("gatling-#{userId}")
  .cleanSession(true)
  .credentials("username", "password")
  .keepAlive(30)
  .qosAtMostOnce()                     // QoS 0 (default)
  // .qosAtLeastOnce()                 // QoS 1
  // .qosExactlyOnce()                 // QoS 2
  .retain(false)
  .reconnectAttemptsMax(3)
  .reconnectDelay(100)
  .reconnectBackoffMultiplier(2.0f)
  .resendDelay(1000)
  .resendBackoffMultiplier(2.0f)
  .timeoutCheckInterval(1)
  .correlateBy(jsonPath("$.correlationId"))
  .unmatchedInboundMessageBufferSize(8);
Scala
val mqttConfig = mqtt
  .broker("localhost", 1883)
  .useTls(false)
  .clientId("gatling-#{userId}")
  .cleanSession(true)
  .credentials("username", "password")
  .keepAlive(30)
  .qosAtMostOnce()
  .retain(false)

Key Protocol Options

OptionDescription
broker(host, port)MQTT broker address and port
useTls(bool)Enable/disable TLS encryption
clientId(expression)Client identifier; supports EL expressions
cleanSession(bool)Start with a clean session (no persistent subscriptions)
credentials(user, pass)Broker authentication
keepAlive(seconds)MQTT keep-alive interval
qosAtMostOnce()QoS level 0 — fire and forget
qosAtLeastOnce()QoS level 1 — at least once delivery
qosExactlyOnce()QoS level 2 — exactly once delivery
retain(bool)Retain the last published message on the broker
reconnectAttemptsMax(n)Maximum reconnection attempts
unmatchedInboundMessageBufferSize(n)Buffer size for unmatched inbound messages

MQTT Actions

All MQTT actions are created with mqtt("actionName").

Connect

Virtual users must connect to the broker before performing any other action. The connect step establishes the MQTT session.
Java
exec(mqtt("connect").connect())
Scala
exec(mqtt("connect").connect())

Subscribe

Subscribe to one or more topics. You can set checks directly on the subscribe action to validate the first received message.
Java
exec(mqtt("subscribe")
  .subscribe("device/#{deviceId}/status")
  .qosAtLeastOnce())
Scala
exec(mqtt("subscribe")
  .subscribe("device/#{deviceId}/status")
  .qosAtLeastOnce())

Publish

Publish a message to a topic. The body API supports the same types as HTTP request bodies.
exec(mqtt("publish telemetry")
  .publish("device/#{deviceId}/telemetry")
  .message(StringBody("{\"temp\": #{temperature}, \"humidity\": #{humidity}}"))
  .qosAtLeastOnce()
  .retain(false))

MQTT Checks

MQTT checks validate messages received after subscribing or publishing. Checks can be blocking (await) or non-blocking (expect).

Blocking Check (await)

The virtual user pauses until a matching message is received or the timeout expires. The first argument is a Duration; the optional second argument narrows the check to a specific reply topic:
Java
exec(mqtt("subscribe with check")
  .subscribe("response/#{deviceId}")
  .await(Duration.ofSeconds(10))
  .check(jsonPath("$.status").is("OK")))

// narrow to a specific reply topic
exec(mqtt("publish with check")
  .publish("commands/#{deviceId}")
  .message(StringBody("{\"cmd\": \"ping\"}"))
  .await(Duration.ofSeconds(10), "response/#{deviceId}")
  .check(jsonPath("$.status").is("OK")))

Non-Blocking Check (expect)

The virtual user continues execution immediately; the check is verified later:
Java
exec(mqtt("publish with expect")
  .publish("commands/#{deviceId}")
  .message(StringBody("{\"cmd\": \"reboot\"}"))
  .expect(Duration.ofSeconds(10))
  .check(jsonPath("$.ack").is("true")))

Wait for All Pending Checks

Use mqtt.waitForMessages() (called on the mqtt DSL object, not on a named action) to block until all pending non-blocking checks have resolved:
Java
mqtt.waitForMessages().timeout(Duration.ofSeconds(30))
Scala
mqtt.waitForMessages.timeout(30.seconds)

Processing Unmatched Messages

Messages that arrive but do not match any active check can be buffered and processed later. Enable buffering by setting unmatchedInboundMessageBufferSize on the protocol. The buffer is reset when:
  • an outbound message is sent
  • processUnmatchedMessages is called
Call mqtt.processUnmatchedMessages on the mqtt DSL object, passing the topic expression and a function:
Java
mqtt.processUnmatchedMessages("#{myTopic}", (messages, session) -> {
  // messages sorted oldest-first; type: MqttInboundMessage
  return session.set("bufferedCount", messages.size());
})
Scala
mqtt.processUnmatchedMessages("#{myTopic}") { (messages, session) =>
  session.set("bufferedCount", messages.size)
}

Full Example

import io.gatling.javaapi.core.*;
import io.gatling.javaapi.mqtt.*;
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.mqtt.MqttDsl.*;
import java.time.Duration;

public class MqttSimulation extends Simulation {

  MqttProtocolBuilder mqttProtocol = mqtt
    .broker("localhost", 1883)
    .clientId("user-#{userId}")
    .cleanSession(true)
    .qosAtLeastOnce();

  ScenarioBuilder scn = scenario("MQTT device simulation")
    .exec(mqtt("connect").connect())
    .exec(mqtt("subscribe")
      .subscribe("device/#{userId}/commands"))
    .repeat(10).on(
      exec(mqtt("publish telemetry")
        .publish("device/#{userId}/telemetry")
        .message(StringBody("{\"temp\": 22.5}"))
        .await(Duration.ofSeconds(5))
        .check(jsonPath("$.status").is("received")))
      .pause(1)
    );

  { setUp(scn.injectOpen(rampUsers(100).during(30))).protocols(mqttProtocol); }
}

Configuration Notes

MQTT support honors the ssl and netty settings from gatling.conf. For TLS connections, set useTls(true) on the protocol and configure the relevant SSL settings in gatling.conf.

Build docs developers (and LLMs) love