Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Client Laravel Package

php-mqtt/laravel-client

Laravel client for MQTT built on php-mqtt/client, making it easy to publish messages and subscribe to topics from Laravel applications. Includes configuration, a facade, and seamless integration with Laravel's container and service provider.

View on GitHub
Deep Wiki
Context7

Getting Started

php-mqtt/laravel-client is a thin Laravel wrapper around php-mqtt/client: a manager + facade + config layer that gives you named broker connections, a broadcasting driver, a queue job, and logging hooks. You still write real MQTT logic against the underlying client.

composer require php-mqtt/laravel-client
php artisan vendor:publish --tag=mqtt-client-config

Set the basics in .env (MQTT_HOST, MQTT_PORT, MQTT_USERNAME, MQTT_PASSWORD, MQTT_CLIENT_ID) and open config/mqtt-client.php first — it is the whole package. Three blocks matter: default_connection, connections.* (host/port/credentials/client_id/mqtt_version), and the per-connection settings (keep-alive, connect timeout, auto-reconnect) plus protocols (MQTT v5-only options such as session expiry and receive maximum). Everything else in the package reads from this file.

The fastest first use case — fire-and-forget publish from a controller or listener:

use PhpMqtt\Client\Facades\MQTT;
use PhpMqtt\Client\QualityOfService;

MQTT::publish(
    'devices/42/state',
    json_encode(['online' => true, 'ts' => now()->timestamp]),
    QualityOfService::QOS_1,
    retain: true,
);

Note there is no connect() call: the manager connects lazily on first use and caches the client. Don't disconnect() after a single publish in a web request unless you have a reason — the connection dies with the request anyway.

Implementation Patterns

Wrap the facade, don't sprinkle it. Create a small MqttPublisher service that takes a connection name and exposes publish(), so you can swap in a fake and so topic naming lives in one place.

final class TelemetryPublisher
{
    public function __construct(private string $connection = 'default') {}

    public function publish(string $topic, array $payload, bool $retain = false): void
    {
        MQTT::connection($this->connection)->publish(
            $topic, json_encode($payload), QualityOfService::QOS_1, $retain
        );
    }
}

Named connections map to broker roles. Keep an internal connection (your own EMQX/Mosquitto) and an iot connection (device-facing broker) side by side; MQTT::connection('iot') is the only switching you need.

Publishing from jobs. The package ships PublishMessageJob for trivial fire-and-forget publishes, but for anything you care about write your own ShouldQueue job — you get $tries, backoff(), failed(), and Horizon visibility, which the shipped job doesn't provide. Keep the payload small; MQTT brokers reject large frames well before Laravel's queue limits bite.

Subscribing is a long-running process, not a request. Put subscriptions in an Artisan command and run it under Supervisor:

public function handle(): int
{
    $client = MQTT::connection('iot');
    $client->subscribe('devices/+/state', function (string $topic, string $message, bool $retained) {
        ProcessDeviceState::dispatch($topic, json_decode($message, true));
    }, QualityOfService::QOS_1);

    $client->loop(true); // blocks
    return self::SUCCESS;
}

In Laravel 11+ use $this->trap(SIGTERM, fn () => $client->interrupt()) (or pcntl_signal) so loop(true) exits cleanly instead of being SIGKILLed mid-write.

Broadcasting for fan-out. Register the mqtt driver in config/broadcasting.php ('driver' => 'mqtt', 'connection' => 'default') and your existing ShouldBroadcast events start publishing to topics derived from channel names. This is the lowest-effort integration if you already use events.

Testing. The manager resolves clients through the MqttClient contract, so $this->mock(MqttClient::class) or a hand-rolled fake bound in the container is the cleanest seam — you don't want unit tests opening sockets. Assert on topic/payload/QoS rather than on broker state.

Gotchas and Tips

  • client_id collisions are the #1 outage cause. Most brokers kick the older session when a duplicate ID connects. Two queue workers sharing MQTT_CLIENT_ID will silently flap all day. Suffix with the hostname/pid, or leave it unset if your broker assigns one.
  • Lazy connect hides misconfiguration until first publish. If you set connect_timeout high and reconnect_automatically on, a wrong host produces a long hang inside a web request. Fail fast in a health check (php artisan tinker → MQTT::connection()->connect()) or set a short connect timeout on web-facing connections.
  • Queue workers and Octane keep stale sockets. Connections cached by the manager survive forks and long idle periods. Call MQTT::connection($name)->disconnect() in a JobProcessing/WorkerStopping listener, or re-resolve per job, otherwise you'll see DataTransferException/ConnectingToBrokerFailedException after ~keep-alive intervals.
  • Retained messages outlive your code. retain: true means the broker replays the last payload to every new subscriber. To clear a retained topic you must publish a zero-length payload with the retain flag — you can't delete it via the manager.
  • QoS ≠ delivery guarantee to your app. QoS 1/2 gets the message to the broker; if your subscriber crashes before acknowledging your own downstream work, it's gone. For anything critical, publish to the broker after your DB transaction commits (DB::afterCommit / dispatchAfterResponse), not inside it.
  • MQTT v5 options live under protocols, not settings. Setting session_expiry_interval on a connection configured as MQTT_3_1_1 is silently inert. Session persistence also requires a stable client_id and clean_session: false — a pairing that trips people up when they later "fix" the duplicate-ID issue by randomising the ID.
  • Exceptions are granular; catch the base class. Everything derives from PhpMqtt\Client\Exceptions\MqttClientException. Catch specific ones (ConnectingToBrokerFailedException, DataTransferException, ProtocolNotSupportedException) for retry decisions, then the base class as a backstop around your publisher.
  • Enable the package logger in non-prod. The logging block in the config (channel + enabled flag) routes the client's internal debug output through your Laravel log — by far the fastest way to see why a handshake is being rejected. Turn it off in production; it's noisy per-packet output.
  • Upgrade note for v1.8.0: this release only widens framework support to Laravel 13.x — no API, config, or behaviour changes. Treat it as a green-light upgrade, but check the php-mqtt/client constraint it pulls and confirm your PHP version meets Laravel 13's floor before bumping on a shared branch.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log