#aws-iot #aws-sdk #mqtt-client #devices #connecting #keep-alive #sync-client

aws-iot-device-sdk-rust

An easy to use SDK for connecting to AWS IoT Core

16 releases (8 breaking)

0.8.1 Apr 10, 2026
0.7.0 Mar 23, 2026
0.6.0 Jan 21, 2025
0.5.0 Dec 12, 2024
0.0.3 Dec 26, 2019

#383 in Network programming

Download history 249/week @ 2026-01-07 548/week @ 2026-01-14 170/week @ 2026-01-21 366/week @ 2026-01-28 287/week @ 2026-02-04 54/week @ 2026-02-11 61/week @ 2026-02-18 377/week @ 2026-02-25 302/week @ 2026-03-04 203/week @ 2026-03-11 390/week @ 2026-03-18 648/week @ 2026-03-25 224/week @ 2026-04-01 800/week @ 2026-04-08 539/week @ 2026-04-15 637/week @ 2026-04-22

2,280 downloads per month
Used in aws-iot-mqtt-cli

MIT license

32KB
481 lines

Documentation crates.io License: MIT

aws-iot-device-sdk-rust

A Rust SDK for connecting IoT devices to AWS IoT Core via MQTT 3.1.1. Built on top of rumqttc with TLS powered by rustls.

Features

  • Async and sync clients for connecting to AWS IoT Core
  • Mutual TLS authentication using X.509 certificates
  • Publish and subscribe to MQTT topics
  • Broadcast incoming messages to multiple receivers
  • Configurable MQTT options (keep-alive, packet size, last will, etc.)

Installation

Add the following to your Cargo.toml:

[dependencies]
aws-iot-device-sdk-rust = "0.8"

By default the async client is enabled. To use the sync client instead:

[dependencies]
aws-iot-device-sdk-rust = { version = "0.8", default-features = false, features = ["sync"] }

You can also enable both:

[dependencies]
aws-iot-device-sdk-rust = { version = "0.8", features = ["sync"] }

Prerequisites

To connect to AWS IoT Core you need:

  1. An AWS IoT thing registered in your account
  2. A root CA certificate (e.g. AmazonRootCA1.pem)
  3. A device certificate (*.crt)
  4. A private key (*.pem)
  5. Your AWS IoT endpoint (found in the AWS IoT Core console under Settings)

Usage

Async client

Create an AWSIoTAsyncClient, spawn an event loop listener on a separate task, and use receivers to process incoming messages. Multiple receivers can be created to fan out messages to different parts of your application.

use aws_iot_device_sdk_rust::{
    async_event_loop_listener, AWSIoTAsyncClient, AWSIoTSettings, Packet, QoS,
};
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let aws_settings = AWSIoTSettings::new(
        "my-device-id".to_owned(),
        "AmazonRootCA1.pem".to_owned(),
        "device-cert.crt".to_owned(),
        "private-key.pem".to_owned(),
        "your-endpoint.iot.region.amazonaws.com".to_owned(),
        None,
    );

    let (iot_core_client, eventloop_stuff) = AWSIoTAsyncClient::new(aws_settings).await?;

    iot_core_client.subscribe("my/topic", QoS::AtMostOnce).await?;
    iot_core_client.publish("my/topic", QoS::AtMostOnce, "hello").await?;

    let mut receiver = iot_core_client.get_receiver().await;

    let recv_thread = tokio::spawn(async move {
        loop {
            if let Ok(event) = receiver.recv().await {
                match event {
                    Packet::Publish(p) => {
                        println!("Topic: {}, Payload: {:?}", p.topic, p.payload);
                    }
                    _ => println!("Other event: {:?}", event),
                }
            }
        }
    });

    let listen_thread = tokio::spawn(async move {
        async_event_loop_listener(eventloop_stuff).await.unwrap();
    });

    tokio::join!(recv_thread, listen_thread);
    Ok(())
}

Sync client

The sync client works the same way but uses std::thread instead of tokio. Enable it with the sync feature.

use aws_iot_device_sdk_rust::{
    sync_client::event_loop_listener, AWSIoTClient, AWSIoTSettings, QoS,
};
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let aws_settings = AWSIoTSettings::new(
        "my-device-id".to_owned(),
        "AmazonRootCA1.pem".to_owned(),
        "device-cert.crt".to_owned(),
        "private-key.pem".to_owned(),
        "your-endpoint.iot.region.amazonaws.com".to_owned(),
        None,
    );

    let (mut iot_core_client, event_loop) = AWSIoTClient::new(aws_settings)?;

    std::thread::spawn(move || event_loop_listener(event_loop));

    iot_core_client.subscribe("my/topic/#", QoS::AtMostOnce)?;

    let mut receiver = iot_core_client.get_receiver()?;

    let recv_thread = std::thread::spawn(move || loop {
        if let Ok(event) = receiver.recv() {
            println!("Received: {:?}", event);
        }
    });

    recv_thread.join().unwrap();
    Ok(())
}

MQTT options

You can customize MQTT connection options by passing MQTTOptionsOverrides to AWSIoTSettings:

use aws_iot_device_sdk_rust::settings::MQTTOptionsOverrides;
use std::time::Duration;

let mut overrides = MQTTOptionsOverrides::default();
overrides.keep_alive = Some(Duration::from_secs(30));
overrides.clean_session = Some(true);
overrides.conn_timeout = Some(10);

let aws_settings = AWSIoTSettings::new(
    "my-device-id".to_owned(),
    "AmazonRootCA1.pem".to_owned(),
    "device-cert.crt".to_owned(),
    "private-key.pem".to_owned(),
    "your-endpoint.iot.region.amazonaws.com".to_owned(),
    Some(overrides),
);

Using the underlying rumqttc client directly

If you need more control, you can retrieve the underlying rumqttc client and work with it directly:

let (iot_core_client, (eventloop, _)) = AWSIoTAsyncClient::new(aws_settings).await?;
let client = iot_core_client.get_client().await;
// Use `client` and `eventloop` with the rumqttc API directly

Error handling

All fallible operations return Result<_, AWSIoTError>. The error type wraps the underlying rumqttc and I/O errors:

Variant Description
AWSConnectionError MQTT connection failure (wraps rumqttc::ConnectionError)
MQTTClientError Client operation failure such as publish/subscribe (wraps rumqttc::ClientError)
IoError File I/O error when reading certificates or keys
MutexError Mutex poisoning (sync client only)
KeyNormalizationError Private key normalization failed: non-UTF-8 key data, malformed PEM structure, invalid base64, unrecognized EC curve, or PKCS8 re-encoding failure

License

This project is licensed under the MIT License.

Dependencies

~14–26MB
~439K SLoC