This comprehensive MQTT review consolidates the entire protocol: the publish-subscribe architecture with central broker, hierarchical topic design with wildcards, three QoS levels trading reliability for overhead, persistent sessions for offline message queuing, retained messages and Last Will Testament for state management, and production concerns including clustering, TLS security, and performance tuning.
This review chapter consolidates everything you’ve learned about MQTT. Here’s a quick mental model to anchor your understanding:
MQTT in One Sentence : A lightweight “postal service” for IoT where devices send messages to a central broker that delivers them to all interested subscribers.
The Five Core Concepts :
Broker
Central server routing all messages
Post office
Publish
Send a message to a topic
Mailing a letter
Subscribe
Register interest in topics
Setting up mail forwarding
Topic
Message category (hierarchical)
Address/mailbox name
QoS
Delivery guarantee level
Registered mail vs regular
When to Use Each QoS Level :
QoS 0 (At most once) : Temperature readings every 5 seconds - missing one is fine
QoS 1 (At least once) : Door sensor alerts - must be delivered, duplicates OK
QoS 2 (Exactly once) : Payment confirmations - no duplicates, no losses
Common Gotcha for Beginners : Wildcards (+ and #) only work in SUBSCRIBE, not PUBLISH. You can subscribe to home/+/temperature but must publish to home/living_room/temperature.
Quick Troubleshooting :
Messages not arriving
QoS 0 + network issues
Use QoS 1
New subscriber misses last value
No retained message
Publish with retain=true
Commands lost while offline
Clean session
Use persistent session (clean_session=false)
Connection drops silently
Keepalive timeout
Reduce keepalive interval
Overview
This comprehensive MQTT review has been organized into focused chapters for easier learning:
Total Estimated Time: 65 minutes
Learning Objectives
By completing all review chapters, you will be able to:
Implement MQTT Clients : Configure publishers and subscribers with appropriate QoS levels, clean/persistent sessions, and TLS authentication for a given IoT scenario
Design Topic Hierarchies : Construct hierarchical MQTT topic schemas using wildcard patterns (+, #) that minimize subscription count and support scalable multi-device deployments
Analyze QoS Trade-offs : Calculate the message overhead, battery penalty, and broker CPU cost for QoS 0, 1, and 2 in a concrete sensor deployment scenario
Evaluate Protocol Selection : Compare MQTT against CoAP, HTTP, and AMQP and justify the choice of protocol based on quantifiable criteria (latency, overhead, delivery semantics)
Diagnose Production Issues : Identify and resolve common MQTT failure modes including session state inconsistency, retained message staleness, and broker throughput bottlenecks
Assess Scalability Designs : Distinguish between single-broker, clustered, and bridged MQTT architectures and select the appropriate topology for a given concurrency and availability requirement
Key Concepts
MQTT : Message Queuing Telemetry Transport — pub/sub protocol optimized for constrained IoT devices over unreliable networks
Broker : Central server routing messages from publishers to all matching subscribers by topic pattern
Topic : Hierarchical string (e.g., home/bedroom/temperature) used to route messages to interested subscribers
QoS Level : Quality of Service 0/1/2 trading delivery guarantee for message overhead
Retained Message : Last message on a topic stored by broker for immediate delivery to new subscribers
Last Will and Testament : Pre-configured message published by broker when a client disconnects ungracefully
Persistent Session : Broker stores subscriptions and pending messages allowing clients to resume after disconnection
Prerequisites
Required Chapters:
Recommended Reading:
Technical Background:
TCP/IP networking basics
Client-server vs pub/sub patterns
Basic security concepts (TLS)
This comprehensive review integrates knowledge across multiple learning resources:
Learning Hubs:
Knowledge Map - Visualize MQTT’s role in the IoT protocol ecosystem
Quizzes Hub - Test your MQTT mastery with interactive assessments
Simulations Hub - Experiment with MQTT broker behavior in a safe environment
Videos Hub - Watch MQTT protocol demonstrations and use cases
Practice Resources:
Related Concepts:
Chapter Navigation
1. Architecture Patterns
MQTT Architecture Patterns covers:
Publish/subscribe architecture with central broker
Topic hierarchies and naming best practices
Wildcard subscription rules (+ and #)
Worked example: Smart building topic design
2. QoS and Reliability
MQTT QoS and Reliability covers:
QoS level selection (0, 1, 2) with trade-offs
Session management (clean vs persistent)
Retained messages for last-known values
Last Will and Testament for failure notification
Keepalive configuration
3. Production Deployment
MQTT Production Deployment covers:
Broker clustering architecture
TLS security and authentication
Performance troubleshooting
Common pitfalls to avoid
CoAP-MQTT protocol bridging
4. Knowledge Check
MQTT Knowledge Check covers:
10 scenario-based multiple choice questions
4 real-world application scenarios
Protocol selection guidance
Before proceeding to the calculators, verify your grasp of the four key MQTT features reviewed above.
Summary
This MQTT comprehensive review synthesizes knowledge across fundamentals, QoS, security, and implementation:
Protocol Selection Criteria : MQTT excels for publish-subscribe event-driven systems with many-to-many communication, while CoAP suits request-response patterns and HTTP works for traditional client-server interactions
QoS Level Trade-offs : QoS 0 provides maximum efficiency (2x fewer packets than QoS 1, 4x fewer packets than QoS 2) for replaceable sensor data, QoS 1 balances reliability and performance for important events, and QoS 2 guarantees exactly-once delivery for critical commands despite highest overhead (4-way handshake)
Wildcard Subscriptions : Single-level (+) and multi-level (#) wildcards enable efficient topic patterns, reducing subscription count from 50 individual topics to a single pattern like home/+/temperature
Session Management : Clean sessions (clean_session=1) suit pure publishers that don’t need offline queuing, while persistent sessions (clean_session=0) with fixed client IDs enable message queuing for devices receiving commands during sleep
Retained Messages : Last published value delivered immediately to new subscribers, essential for device status and slow-changing state data
Production Security : MQTT over TLS (port 8883) with username/password authentication, client certificates for mutual authentication, and topic-level ACLs prevent unauthorized access and eavesdropping
Scalability Challenges : Broker clustering and load balancing address throughput bottlenecks, with modern brokers handling 100K-1M concurrent connections when properly optimized with QoS selection and message batching
Interactive Calculators
MQTT QoS Energy Impact Calculator
Estimate the battery impact of different QoS levels for your sensor deployment.
Show code
viewof qosNumSensors = Inputs. range ([10 , 10000 ], {
value : 1000 , step : 10 , label : "Number of sensors:"
})
viewof qosReportInterval = Inputs. range ([1 , 3600 ], {
value : 60 , step : 1 , label : "Report interval (seconds):"
})
viewof qosPayloadSize = Inputs. range ([10 , 1024 ], {
value : 50 , step : 1 , label : "Payload size (bytes):"
})
viewof qosBatteryCapacity = Inputs. range ([100 , 10000 ], {
value : 2500 , step : 100 , label : "Battery capacity (mAh):"
})
Show code
qosResults = {
const msgsPerDay = (86400 / qosReportInterval);
const totalMsgsPerDay = qosNumSensors * msgsPerDay;
const radioTimeMs = (qosPayloadSize * 8 ) / 250000 * 1000 ;
const energyPerMsg = 30 * radioTimeMs / 3600 ;
const ackEnergy = 10 * 5 / 3600 ;
const ack3Energy = 10 * 15 / 3600 ;
const qos0Daily = msgsPerDay * energyPerMsg;
const qos1Daily = msgsPerDay * (energyPerMsg + ackEnergy);
const qos2Daily = msgsPerDay * (energyPerMsg + ack3Energy);
const qos0Life = qosBatteryCapacity / qos0Daily;
const qos1Life = qosBatteryCapacity / qos1Daily;
const qos2Life = qosBatteryCapacity / qos2Daily;
return {
msgsPerDay, totalMsgsPerDay,
qos0Daily : qos0Daily. toFixed (2 ),
qos1Daily : qos1Daily. toFixed (2 ),
qos2Daily : qos2Daily. toFixed (2 ),
qos0Life : qos0Life. toFixed (1 ),
qos1Life : qos1Life. toFixed (1 ),
qos2Life : qos2Life. toFixed (1 ),
qos1Penalty : (qos1Daily / qos0Daily). toFixed (2 ),
qos2Penalty : (qos2Daily / qos0Daily). toFixed (2 ),
totalPacketsQos0 : (totalMsgsPerDay). toLocaleString (),
totalPacketsQos1 : (totalMsgsPerDay * 2 ). toLocaleString (),
totalPacketsQos2 : (totalMsgsPerDay * 4 ). toLocaleString ()
};
}
Show code
html `<div class="mqtt-review-panel" style="border-left: 4px solid #16A085;">
<h4 style="color: #2C3E50; margin-top: 0;">Energy Analysis Results</h4>
<p style="color: #7F8C8D; margin-bottom: 1rem;">Messages per sensor per day: <strong> ${ qosResults. msgsPerDay . toLocaleString ()} </strong> | Total fleet messages: <strong> ${ qosResults. totalMsgsPerDay . toLocaleString ()} </strong>/day</p>
<div class="mqtt-review-grid mqtt-review-grid--three">
<div class="mqtt-review-card" style="border-top: 4px solid #16A085;">
<div class="mqtt-review-value" style="color: #16A085;">QoS 0</div>
<div class="mqtt-review-stat-list">
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Daily energy</span><span> ${ qosResults. qos0Daily } mAh</span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Battery life</span><span> ${ qosResults. qos0Life } days</span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Battery penalty</span><span style="color: #16A085; font-weight: bold;">1.00x baseline</span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Broker packets/day</span><span> ${ qosResults. totalPacketsQos0 } </span></div>
</div>
</div>
<div class="mqtt-review-card" style="border-top: 4px solid #E67E22;">
<div class="mqtt-review-value" style="color: #E67E22;">QoS 1</div>
<div class="mqtt-review-stat-list">
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Daily energy</span><span> ${ qosResults. qos1Daily } mAh</span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Battery life</span><span> ${ qosResults. qos1Life } days</span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Battery penalty</span><span style="color: #E67E22; font-weight: bold;"> ${ qosResults. qos1Penalty } x</span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Broker packets/day</span><span> ${ qosResults. totalPacketsQos1 } </span></div>
</div>
</div>
<div class="mqtt-review-card" style="border-top: 4px solid #E74C3C;">
<div class="mqtt-review-value" style="color: #E74C3C;">QoS 2</div>
<div class="mqtt-review-stat-list">
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Daily energy</span><span> ${ qosResults. qos2Daily } mAh</span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Battery life</span><span> ${ qosResults. qos2Life } days</span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Battery penalty</span><span style="color: #E74C3C; font-weight: bold;"> ${ qosResults. qos2Penalty } x</span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Broker packets/day</span><span> ${ qosResults. totalPacketsQos2 } </span></div>
</div>
</div>
</div>
</div>`
MQTT Broker Throughput Calculator
Estimate broker resource requirements for your MQTT deployment.
Show code
viewof brokerDevices = Inputs. range ([100 , 100000 ], {
value : 5000 , step : 100 , label : "Connected devices:"
})
viewof brokerMsgRate = Inputs. range ([0.1 , 100 ], {
value : 1 , step : 0.1 , label : "Messages per device per second:"
})
viewof brokerAvgPayload = Inputs. range ([10 , 2048 ], {
value : 100 , step : 10 , label : "Average payload (bytes):"
})
viewof brokerSubscribers = Inputs. range ([1 , 100 ], {
value : 3 , step : 1 , label : "Average subscribers per topic:"
})
Show code
brokerResults = {
const inboundRate = brokerDevices * brokerMsgRate;
const outboundRate = inboundRate * brokerSubscribers;
const totalRate = inboundRate + outboundRate;
const mqttOverhead = 4 ;
const tcpOverhead = 40 ;
const totalPerMsg = brokerAvgPayload + mqttOverhead + tcpOverhead;
const inboundBandwidth = inboundRate * totalPerMsg * 8 ;
const outboundBandwidth = outboundRate * totalPerMsg * 8 ;
const totalBandwidth = inboundBandwidth + outboundBandwidth;
const formatBandwidth = (bps) => {
if (bps >= 1e9 ) return (bps / 1e9 ). toFixed (2 ) + " Gbps" ;
if (bps >= 1e6 ) return (bps / 1e6 ). toFixed (2 ) + " Mbps" ;
if (bps >= 1e3 ) return (bps / 1e3 ). toFixed (2 ) + " Kbps" ;
return bps. toFixed (0 ) + " bps" ;
};
const estimatedCores = Math . max (1 , Math . ceil (totalRate / 50000 ));
const estimatedRamMB = Math . ceil (brokerDevices * 0.05 + (totalRate * 0.001 ));
const capacityPct = Math . min (100 , (totalRate / 1000000 ) * 100 );
return {
inboundRate : inboundRate. toLocaleString (),
outboundRate : outboundRate. toLocaleString (),
totalRate : totalRate. toLocaleString (),
inboundBw : formatBandwidth (inboundBandwidth),
outboundBw : formatBandwidth (outboundBandwidth),
totalBw : formatBandwidth (totalBandwidth),
estimatedCores,
estimatedRamMB,
capacityPct : capacityPct. toFixed (1 ),
dailyMessages : (totalRate * 86400 ). toLocaleString ()
};
}
Show code
html `<div class="mqtt-review-panel" style="border-left: 4px solid #3498DB;">
<h4 style="color: #2C3E50; margin-top: 0;">Broker Capacity Estimate</h4>
<div class="mqtt-review-grid mqtt-review-grid--two">
<div class="mqtt-review-card">
<div style="color: #7F8C8D; font-size: 0.85rem;">Inbound Message Rate</div>
<div style="color: #3498DB; font-size: 1.4rem; font-weight: bold;"> ${ brokerResults. inboundRate } msg/s</div>
<div style="color: #7F8C8D; font-size: 0.85rem;">Bandwidth: ${ brokerResults. inboundBw } </div>
</div>
<div class="mqtt-review-card">
<div style="color: #7F8C8D; font-size: 0.85rem;">Outbound Message Rate</div>
<div style="color: #E67E22; font-size: 1.4rem; font-weight: bold;"> ${ brokerResults. outboundRate } msg/s</div>
<div style="color: #7F8C8D; font-size: 0.85rem;">Bandwidth: ${ brokerResults. outboundBw } </div>
</div>
<div class="mqtt-review-card">
<div style="color: #7F8C8D; font-size: 0.85rem;">Estimated CPU Cores</div>
<div style="color: #9B59B6; font-size: 1.4rem; font-weight: bold;"> ${ brokerResults. estimatedCores } cores</div>
<div style="color: #7F8C8D; font-size: 0.85rem;">RAM: ~ ${ brokerResults. estimatedRamMB } MB</div>
</div>
<div class="mqtt-review-card">
<div style="color: #7F8C8D; font-size: 0.85rem;">Daily Messages (Total)</div>
<div style="color: #16A085; font-size: 1.4rem; font-weight: bold;"> ${ brokerResults. dailyMessages } </div>
<div style="color: #7F8C8D; font-size: 0.85rem;">Total bandwidth: ${ brokerResults. totalBw } </div>
</div>
</div>
<div style="margin-top: 1rem; background: white; padding: 0.75rem 1rem; border-radius: 6px; border: 1px solid #d5dbdb;">
<div style="display: flex; justify-content: space-between; margin-bottom: 4px;">
<span style="color: #2C3E50; font-weight: bold; font-size: 0.9rem;">Single-Broker Capacity Usage</span>
<span style="color: ${ brokerResults. capacityPct > 80 ? '#E74C3C' : brokerResults. capacityPct > 50 ? '#E67E22' : '#16A085' } ; font-weight: bold;"> ${ brokerResults. capacityPct } %</span>
</div>
<div style="background: #ecf0f1; border-radius: 4px; height: 12px; overflow: hidden;">
<div style="background: ${ brokerResults. capacityPct > 80 ? '#E74C3C' : brokerResults. capacityPct > 50 ? '#E67E22' : '#16A085' } ; height: 100%; width: ${ Math . min (100 , brokerResults. capacityPct )} %; border-radius: 4px; transition: width 0.3s;"></div>
</div>
<div style="color: #7F8C8D; font-size: 0.8rem; margin-top: 4px;"> ${ brokerResults. capacityPct > 80 ? 'Consider broker clustering for high availability' : brokerResults. capacityPct > 50 ? 'Monitor closely; plan for scaling' : 'Healthy capacity - single broker sufficient' } </div>
</div>
</div>`
MQTT Message Overhead Comparison
Compare the per-message byte overhead across QoS levels and protocol options.
Show code
viewof ohPayload = Inputs. range ([1 , 4096 ], {
value : 50 , step : 1 , label : "Application payload (bytes):"
})
viewof ohTopicLen = Inputs. range ([5 , 200 ], {
value : 30 , step : 1 , label : "Topic string length (bytes):"
})
viewof ohUseTls = Inputs. toggle ({label : "TLS encryption (port 8883):" , value : false })
Show code
ohResults = {
const fixedHeader = 2 ;
const varHeader = 2 + ohTopicLen;
const mqttTotal = fixedHeader + varHeader + ohPayload;
const qos1Extra = 2 ;
const qos2Extra = 2 ;
const qos0Size = mqttTotal;
const qos1Size = mqttTotal + qos1Extra;
const qos2Size = mqttTotal + qos2Extra;
const tcpIpOverhead = 40 ;
const tlsOverhead = ohUseTls ? 29 : 0 ;
const wireQos0 = qos0Size + tcpIpOverhead + tlsOverhead;
const wireQos1 = qos1Size + tcpIpOverhead + tlsOverhead;
const wireQos2 = qos2Size + tcpIpOverhead + tlsOverhead;
const qos0Eff = (ohPayload / wireQos0 * 100 ). toFixed (1 );
const qos1Eff = (ohPayload / wireQos1 * 100 ). toFixed (1 );
const qos2Eff = (ohPayload / wireQos2 * 100 ). toFixed (1 );
const coapSize = 4 + ohTopicLen + ohPayload + tcpIpOverhead - 12 ;
const httpSize = 200 + ohPayload + tcpIpOverhead + tlsOverhead;
return {
qos0Size, qos1Size, qos2Size,
wireQos0, wireQos1, wireQos2,
qos0Eff, qos1Eff, qos2Eff,
coapSize, httpSize,
mqttOverhead : (fixedHeader + varHeader). toFixed (0 ),
tlsNote : ohUseTls ? "TLS adds ~29 bytes per record" : "No TLS overhead"
};
}
Show code
html `<div class="mqtt-review-panel" style="border-left: 4px solid #E67E22;">
<h4 style="color: #2C3E50; margin-top: 0;">Message Size Breakdown</h4>
<p style="color: #7F8C8D; margin-bottom: 1rem;">MQTT header overhead: <strong> ${ ohResults. mqttOverhead } bytes</strong> | ${ ohResults. tlsNote } </p>
<div class="mqtt-review-grid mqtt-review-grid--three">
<div class="mqtt-review-card" style="border-top: 4px solid #16A085;">
<div class="mqtt-review-value" style="color: #16A085;">MQTT QoS 0</div>
<div class="mqtt-review-stat-list">
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">MQTT bytes</span><span> ${ ohResults. qos0Size } </span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">On-wire bytes</span><span> ${ ohResults. wireQos0 } </span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Payload efficiency</span><span> ${ ohResults. qos0Eff } %</span></div>
</div>
</div>
<div class="mqtt-review-card" style="border-top: 4px solid #E67E22;">
<div class="mqtt-review-value" style="color: #E67E22;">MQTT QoS 1</div>
<div class="mqtt-review-stat-list">
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">MQTT bytes</span><span> ${ ohResults. qos1Size } </span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">On-wire bytes</span><span> ${ ohResults. wireQos1 } </span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Payload efficiency</span><span> ${ ohResults. qos1Eff } %</span></div>
</div>
</div>
<div class="mqtt-review-card" style="border-top: 4px solid #E74C3C;">
<div class="mqtt-review-value" style="color: #E74C3C;">MQTT QoS 2</div>
<div class="mqtt-review-stat-list">
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">MQTT bytes</span><span> ${ ohResults. qos2Size } </span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">On-wire bytes</span><span> ${ ohResults. wireQos2 } </span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Payload efficiency</span><span> ${ ohResults. qos2Eff } %</span></div>
</div>
</div>
<div class="mqtt-review-card" style="border-top: 4px solid #9B59B6;">
<div class="mqtt-review-value" style="color: #9B59B6;">CoAP (UDP)</div>
<div class="mqtt-review-stat-list">
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">MQTT bytes</span><span>-</span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">On-wire bytes</span><span> ${ ohResults. coapSize } </span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Payload efficiency</span><span> ${ (ohPayload / ohResults. coapSize * 100 ). toFixed (1 )} %</span></div>
</div>
</div>
<div class="mqtt-review-card" style="border-top: 4px solid #3498DB;">
<div class="mqtt-review-value" style="color: #3498DB;">HTTP POST</div>
<div class="mqtt-review-stat-list">
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">MQTT bytes</span><span>-</span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">On-wire bytes</span><span> ${ ohResults. httpSize } </span></div>
<div class="mqtt-review-stat-row"><span class="mqtt-review-label">Payload efficiency</span><span> ${ (ohPayload / ohResults. httpSize * 100 ). toFixed (1 )} %</span></div>
</div>
</div>
</div>
</div>`
MQTT Topic Wildcard Savings Calculator
Estimate how wildcard subscriptions reduce the number of individual topic subscriptions needed.
Show code
viewof wcLocations = Inputs. range ([1 , 50 ], {
value : 10 , step : 1 , label : "Number of locations:"
})
viewof wcDevicesPerLoc = Inputs. range ([1 , 100 ], {
value : 5 , step : 1 , label : "Devices per location:"
})
viewof wcSensorTypes = Inputs. range ([1 , 20 ], {
value : 3 , step : 1 , label : "Sensor types per device:"
})
Show code
wcResults = {
const individual = wcLocations * wcDevicesPerLoc * wcSensorTypes;
const singleLevel = wcLocations * wcSensorTypes;
const multiLevel = 1 ;
const singleSavings = ((1 - singleLevel / individual) * 100 ). toFixed (1 );
const multiSavings = ((1 - multiLevel / individual) * 100 ). toFixed (1 );
return {
individual,
singleLevel,
multiLevel,
singleSavings,
multiSavings,
exampleTopic : `building/ ${ wcLocations > 1 ? "floor1" : "main" } / ${ wcDevicesPerLoc > 1 ? "device1" : "sensor" } /temperature` ,
singleWildcard : `building/+/ ${ wcDevicesPerLoc > 1 ? "device1" : "sensor" } /temperature` ,
multiWildcard : `building/#`
};
}
Show code
html `<div class="mqtt-review-panel" style="border-left: 4px solid #9B59B6;">
<h4 style="color: #2C3E50; margin-top: 0;">Wildcard Subscription Analysis</h4>
<p style="color: #7F8C8D;">Topic pattern: <code class="mqtt-review-code"> ${ wcResults. exampleTopic } </code></p>
<div class="mqtt-review-grid mqtt-review-grid--three">
<div class="mqtt-review-card mqtt-review-card--center" style="border: 2px solid #E74C3C;">
<div style="color: #7F8C8D; font-size: 0.85rem;">No Wildcards</div>
<div style="color: #E74C3C; font-size: 2rem; font-weight: bold;"> ${ wcResults. individual } </div>
<div style="color: #7F8C8D; font-size: 0.85rem;">individual subscriptions</div>
</div>
<div class="mqtt-review-card mqtt-review-card--center" style="border: 2px solid #E67E22;">
<div style="color: #7F8C8D; font-size: 0.85rem;">Single-Level (+)</div>
<div style="color: #E67E22; font-size: 2rem; font-weight: bold;"> ${ wcResults. singleLevel } </div>
<div style="color: #7F8C8D; font-size: 0.85rem;"> ${ wcResults. singleSavings } % reduction</div>
</div>
<div class="mqtt-review-card mqtt-review-card--center" style="border: 2px solid #16A085;">
<div style="color: #7F8C8D; font-size: 0.85rem;">Multi-Level (#)</div>
<div style="color: #16A085; font-size: 2rem; font-weight: bold;"> ${ wcResults. multiLevel } </div>
<div style="color: #7F8C8D; font-size: 0.85rem;"> ${ wcResults. multiSavings } % reduction</div>
</div>
</div>
<div class="mqtt-review-card" style="padding: 0.75rem 1rem; margin-top: 0.5rem;">
<div style="font-size: 0.9rem; color: #2C3E50;">
<strong>Example:</strong> With <strong> ${ wcLocations} </strong> locations x <strong> ${ wcDevicesPerLoc} </strong> devices x <strong> ${ wcSensorTypes} </strong> sensor types = <strong> ${ wcResults. individual } </strong> unique topics.<br>
Using <code class="mqtt-review-code">location/+/sensorType</code> reduces to <strong> ${ wcResults. singleLevel } </strong> subscriptions.
Using <code class="mqtt-review-code">building/#</code> captures everything in <strong>1</strong> subscription.
</div>
</div>
</div>`
Use this framework to select the appropriate QoS level for different message types in your MQTT deployment:
Sensor telemetry (frequent)
QoS 0
Next reading supersedes previous; 1-5% loss acceptable
Lowest latency, minimal broker load
Alert notifications
QoS 1
Must deliver at least once; duplicates handled by application
Moderate overhead, good reliability
Actuator commands
QoS 1 or 2
Command execution critical; QoS 2 if duplicates cause harm
Higher latency, guaranteed delivery
Configuration updates
QoS 2
Exactly-once ensures consistent state; no duplicate config application
Highest overhead, strong guarantee
Heartbeat/keepalive
QoS 0
Periodic signal; single miss won’t trigger alarm
Minimal overhead
Device status (retained)
QoS 1 + retain
Last status must reach new subscribers reliably
Stored on broker, moderate cost
Financial transactions
QoS 2
No duplicate payments; exactly-once essential
High latency acceptable for correctness
Performance Comparison:
QoS 0
1 (fire-and-forget)
1× baseline
10ms
5% messages lost permanently
QoS 1
2 (PUBLISH + PUBACK)
2× baseline
25ms
All delivered, ~5% duplicates
QoS 2
4 (PUBLISH + PUBREC + PUBREL + PUBCOMP)
4× baseline
60ms
All delivered, zero duplicates
MQTT QoS levels have dramatic battery and broker scaling impacts. Let’s quantify for a 1,000-sensor deployment:
Scenario: 1,000 sensors report every 60 seconds, 50-byte payloads.
QoS 0 analysis:
Messages/day/sensor: 1,440
Total broker throughput: \(1{,}000 \times 1{,}440 = 1{,}440{,}000\) msg/day
Radio time/message: \(\frac{50 \times 8}{250{,}000} = 1.6\) ms @ 30 mA = 0.013 mAh
Daily energy/sensor: \(1{,}440 \times 0.013 = 18.7\) mAh
Broker load: 1.44M messages × 1 packet = 1.44M packets/day
QoS 1 analysis (2× overhead): - Broker load: 1.44M × 2 (PUBLISH + PUBACK) = 2.88M packets/day - ACK wait time: 5 ms @ 10 mA = 0.014 mAh - Daily energy: \(1{,}440 \times (0.013 + 0.014) = 38.9\) mAh - Battery penalty: \(\frac{38.9}{18.7} = 2.08\times\) vs QoS 0
QoS 2 analysis (4× overhead): - Broker load: 1.44M × 4 (4-way handshake) = 5.76M packets/day - 3 ACK phases: 15 ms @ 10 mA = 0.042 mAh - Daily energy: \(1{,}440 \times (0.013 + 0.042) = 79.2\) mAh - Battery penalty: \(\frac{79.2}{18.7} = 4.24\times\) vs QoS 0
Broker CPU scaling: At 1.44M msg/day baseline (QoS 0), Mosquitto on 2-core @ 2 GHz uses ~5% CPU. QoS 2 → 20% CPU.
Worked Example: Smart Factory with 1,000 Sensors
Scenario: 1,000 temperature sensors report every 10 seconds; 100 actuators receive commands hourly.
QoS 0 for sensors
Messages/hour: 1,000 x 360 = 360,000
Broker work: 360,000 messages, no ACK packets
5% packet loss: about 18,000 readings lost
Impact: acceptable because the next reading arrives in 10 seconds
Bandwidth: about 18 MB/hour at 50 bytes per reading
QoS 1 for actuators
Commands/hour: 100
Broker work: 200 packets, including PUBACKs
5% retry rate: about 5 duplicate commands
Impact: acceptable when commands include an idempotent command ID
Bandwidth: about 10 KB/hour
If sensors incorrectly used QoS 1
Messages/hour: doubles to 720,000 packets with ACKs
Broker CPU: roughly 2x increase
Bandwidth: roughly 36 MB/hour
Benefit: zero reading loss
Trade-off: not worth it because the next reading quickly replaces a lost one
If actuators incorrectly used QoS 0
Lost commands: about 5 per hour at 5% packet loss
Impact: valves may not actuate and production can stop
Cost: operational downtime dominates the tiny ACK overhead
Trade-off: unacceptable risk for minimal bandwidth savings
Key Insights:
Don’t over-specify: QoS 1 for all messages wastes 50%+ bandwidth/CPU for replaceable sensor data
Don’t under-specify: QoS 0 for commands risks operational failures worth far more than the ACK overhead
Use retain strategically: Device status with retain=true + QoS 1 ensures new subscribers get last known state
Hybrid architectures work best: QoS 0 for high-volume telemetry, QoS 1 for important events, QoS 2 for critical transactions
Production Recommendation:
Default: QoS 0 (assume sensor telemetry)
Exceptions: QoS 1 for alerts/commands/device status
Rare: QoS 2 only for financial/legal/safety-critical operations where duplicates cause actual harm
Concept Relationships
MQTT as a comprehensive protocol connects to many IoT system concepts:
Protocol Fundamentals:
Alternative Protocols:
System Integration:
Edge Gateway Patterns - MQTT broker placement
Message Broker Architecture - Scaling brokers
Cloud Integration - AWS IoT Core, Azure IoT Hub
Transport Layer:
TCP Fundamentals - Underlying reliable transport
TLS/SSL Security - Encryption for MQTT over port 8883
Network Reliability - How QoS works with TCP
Prerequisites You Should Know:
TCP provides ordered, reliable delivery - MQTT builds on this
Publish-subscribe pattern decouples producers from consumers
Quality of Service (QoS) levels trade reliability for overhead
Broker clustering enables horizontal scaling beyond single-node limits
What This Enables:
Design scalable IoT systems handling millions of devices
Select appropriate QoS levels based on application requirements
Implement secure MQTT with TLS and topic-level ACLs
Compare MQTT with CoAP/HTTP for protocol selection decisions
See Also
MQTT Deep Dives:
Protocol Comparisons:
CoAP vs MQTT - When to use each
AMQP vs MQTT - Enterprise vs IoT messaging
Protocol Selection Guide - Decision framework
Broker Technologies:
Specifications:
What’s Next
Now that you have reviewed the full MQTT protocol, explore related IoT messaging protocols and system-level topics:
Chapter
Focus: UDP-based request-response protocol for constrained devices.
Why read it: Understand when CoAP outperforms MQTT for battery-powered sensors, CoAP Observe patterns, and RESTful IoT design.
Chapter
Focus: Side-by-side protocol selection framework.
Why read it: Apply a structured decision process for latency, power, topology, and reliability constraints.
Chapter
Focus: Enterprise message queuing with exchanges, queues, and bindings.
Why read it: Evaluate when AMQP’s richer routing model is a better fit for back-end IoT pipelines than simple MQTT pub/sub.
Chapter
Focus: When to use AMQP and MQTT in the same system.
Why read it: Design hybrid architectures that pair MQTT for device-to-cloud messaging with AMQP for cloud service routing.
Chapter
Focus: MQTT 5.0 features, packet structure, and topic design patterns.
Why read it: Implement shared subscriptions, topic aliases, user properties, and other production-grade MQTT 5.0 enhancements.
Chapter
Focus: Hands-on ESP32 MQTT projects with Mosquitto and Node-RED.
Why read it: Build working prototypes that use MQTT QoS, retained messages, and TLS on real hardware.