I have followed these docs to make cloud-to-device-messages work. Sending the C2D message with IoTHubRegistryManager in the backend works: I can confirm in the portal that on that specific device C2D messages queued says 1 after I run it. The only problem is that on the receiver end (the device) that C2D message is not being consumed by the on_message_received listener, I am not sure why. I have double checked that it is the same device. Below is my code on the device end (simplified and stripped of all irrelevant stuff), see my comments: class RunnerClass: def __init__(self): self.iot_client: IoTHubModuleClient async def device_twin_patch_handler(self, patch: dict) -> None: # this triggers when the twin gets updated (works) logging.info("Handle incoming patch.") async def connection_change_handler(self) -> None: # this triggers when the connection changes (works) logging.info("Connection change detected...") async def receive_message_handler(self, message: Message) -> None: # this method is not triggering when C2D message ends up in device queue logging.info("Received optimization response:") for property in vars(message).items(): logging.info(f"\t{property}") async def create_iot_client(self) -> None: self.iot_client: IoTHubModuleClient = IoTHubModuleClient.create_from_edge_environment() await self.iot_client.connect() self.iot_client.on_message_received = self.receive_message_handler self.iot_client.on_twin_desired_properties_patch_received = self.device_twin_patch_handler self.iot_client.on_connection_state_change = self.connection_change_handler I can confirm that the other handler methods are triggering properly. Only receive_message_handler is not being called by on_message_received listener when the C2D message ends up in the device queue. Am I missing some sort of configuration? I am using standard tier IoT Hub. Continue reading...