TL;DR. Azure IoT Hub pricing charges by message, not by byte, so the hub bill is set once, by how the plant gateway packs readings. For a hypothetical plant with 2,000 sensor tags read once a second, one message per reading needs an S3 unit at $2,500 a month; 36 readings per message fit on one S2 unit at $250. After that the hub stays flat and the bill grows downstream: kept in Hot blob storage, the raw readings cost more than the hub from month 24 and reach $388 a month by month 36. A lifecycle rule holds the same data for $43.
Azure IoT Hub pricing is a daily message quota sold in units: you buy enough units for your busiest day, and every message counts in 4 KB blocks. That makes the hub a design decision more than a usage bill. Pack readings well at the edge and the hub becomes the cheap, flat part of a plant's sensor bill. Storage and queries become the part that grows.
Below, one plant priced from Azure's list prices (East US, read from the Azure Retail Prices API on October 28, 2026), from device to storage to queries. It is a worked model, not a measured benchmark: no plant ran.
IoT Hub sells daily message quotas, metered in 4 KB blocks
| Edition | Price per unit per month | Messages per day per unit |
|---|---|---|
| Free | $0 | 8,000 (0.5 KB blocks) |
| B1 / S1 | $10 / $25 | 400,000 |
| B2 / S2 | $50 / $250 | 6,000,000 |
| B3 / S3 | $500 / $2,500 | 300,000,000 |
Prices from the retail price API; quotas from Microsoft's IoT Hub pricing page.
Four rules decide the bill:
- Messages count in 4 KB blocks. Microsoft's billing guide: "a 100-byte message is charged as one message, and a 6-KB message is charged as two messages." Device-to-cloud messages are charged "on ingress into IoT Hub."
- Twins and methods use the same quota. Twin reads, twin updates and direct methods are all charged as messages in 4 KB chunks, on the same daily allowance.
- The quota is per UTC day. Past it, requests fail with 403002 IotHubQuotaExceeded until you "increase the number of units on the IoT hub or wait for the next UTC day for the daily quota to refresh."
- Basic is cheaper but one-way. Basic tiers lack cloud-to-device messages, device twins and IoT Edge, per the pricing page. A plant gateway running IoT Edge needs Standard.
Units scale in steps: up to 200 units of size 1 or 2, or 10 of size 3, per Microsoft's sizing guide.
The same plant costs $2,500 or $250 a month, depending on the gateway
Consider a hypothetical plant with 2,000 sensor tags (temperatures, pressures, motor currents) read once a second through one IoT Edge gateway. Each reading is a 100-byte JSON record. That is 2,000 x 86,400 = 172.8 million readings a day.
| Gateway design | Messages a day | Cheapest Standard hub | Per month |
|---|---|---|---|
| One message per reading | 172,800,000 | 1 x S3 (58% of quota) | $2,500 |
| 36 readings per message (3.6 KB) | 4,800,000 | 1 x S2 (80% of quota) | $250 |
| 1-minute min, max and mean per tag, 36 per message | 80,000 | 1 x S1 (20% of quota) | $25 |
The first row cannot run on S1 at all: it would need 432 units, over the 200 cap. On S2 it takes 29 units, $7,250. Microsoft's own Example #3 makes the same point at small scale: 40 reads of 100 bytes cost 40 messages sent one by one, or one message batched.
The throttle points the same way. S1 accepts the "higher of 100 send operations/sec or 12 send operations/sec/unit," S2 120 per second per unit, per the quotas page. One message per reading is 2,000 sends a second; the batched design is about 56.
The batched design has a cliff. At 80% of one S2 unit, 500 more tags at 1 Hz bring the plant to exactly 6,000,000 messages a day. The next tag past that means a second unit, and the hub bill doubles to $500.
Leave headroom in each batch (here, about 500 bytes): for messages "which have properties and body," Microsoft computes the size over both, so a 4 KB body plus properties spills into a second block.
After batching, the bill grows downstream
The hub's job ends at ingress. A common path for the readings after it: an IoT Hub route writes them to Blob Storage or ADLS Gen2 (Avro by default, JSON if set, per the endpoints guide), and Azure Data Explorer (ADX) ingests them for queries and dashboards.
At 100 bytes a reading, the plant writes 17.28 GB of payload a day, 518.4 GB a month. Here is what each piece costs at East US list price:
| Line | Arithmetic | Per month |
|---|---|---|
| IoT Hub, batched | 1 x S2 | $250 |
| ADX engine, two-node floor | 2 nodes x 730 h x ($0.144 E2d v5 Linux VM + 2 vCores x $0.11 markup) | $531.44 |
| Hot blob, month 12 | 6,220.8 GB x $0.0208 | $129.39 |
| Hot blob, month 36 | 18,662.4 GB x $0.0208 | $388.18 |
Sources: Blob Storage and E2d v5 in the retail price API, and the ADX pricing page, whose own example bills "8 instances x 8 vCores/instance x $0.11/vCore". A production ADX cluster has "at least two nodes for the engine cluster and at least two nodes for the data management cluster"; the floor above leaves out the data management nodes, ADX storage and networking.
Two lines are flat and one is not. The hub and the ADX engine cost the same in month 36 as in month 1. The Hot blob line adds about $10.78 every month, because nobody set a retention rule, and passes the hub in month 24. By month 36 the hub is 21% of $1,170; with one message per reading it would have been 73% of $3,420.
Three habits make the downstream line steeper than this model:
- Sampling rates nobody revisited. A tank temperature that moves over minutes, read once a second, is 60 times the rows of a one-minute summary.
- Raw readings kept forever by default. A new ADX table has no retention policy, and the default policy object, once applied, is a soft-delete period of "1,000 years".
- The same readings in three places. If the plant also keeps them in an on-site historian, the cloud holds a second copy in blob and a third in ADX, each billed on its own.
Cut the bill at three points: the gateway, the tier, the cache
Batch at the gateway. Pack readings to just under 4 KB per message. In this model it is the difference between $2,500 and $250 a month, and it costs a few seconds of latency per batch.
Aggregate where nobody reads the raw signal. A one-minute min, max and mean per tag cuts the hub to one S1 unit and the stored volume to 8.64 GB a month. Keep raw readings only for the tags someone analyses at full resolution, such as vibration on critical motors.
Tier the raw archive. Microsoft's lifecycle example moves blobs to Cool after 30 days and Archive after 90:
{
"rules": [
{
"name": "telemetryAging",
"enabled": true,
"type": "Lifecycle",
"definition": {
"filters": { "blobTypes": [ "blockBlob" ], "prefixMatch": [ "telemetry/" ] },
"actions": {
"baseBlob": {
"tierToCool": { "daysAfterModificationGreaterThan": 30 },
"tierToArchive": { "daysAfterModificationGreaterThan": 90 }
}
}
}
}
]
}
At $0.0152 per GB for Cool and $0.00099 for Archive, month 36 drops from $388 to $43. Archive is offline: Microsoft describes it as "on the order of hours" to read back, with a 180-day minimum (access tiers). Cool has a 30-day minimum, and deleting earlier is charged pro rata.
Shorten the ADX hot cache and set retention. ADX keeps hot data "in local SSD storage", so the cache window sets how many engine nodes you need. Set both on the telemetry table:
.alter table PlantTelemetry policy caching hot = 30d .alter-merge table PlantTelemetry policy retention softdelete = 365d
Measure quota use and readers before you change anything
Before cutting units or retention, check what the hub uses and who reads the data. The daily peak of dailyMessageQuotaUsed ("Number of total messages used today") is the number to size against:
az monitor metrics list --resource <iot-hub-resource-id> \ --metrics dailyMessageQuotaUsed --aggregation Maximum \ --interval 24h --offset 30d
Add d2c.telemetry.ingress.sendThrottle (throttling errors) to see whether the hub is short of capacity, and d2c.endpoints.egress.storage.bytes to see how many bytes routing writes to storage each day. If the daily peak stays well under one unit's quota for a month, you are paying for a unit you do not use.
Then ask who reads the readings. In ADX, .show queries lists completed queries with their text and user; a Database Admin or Database Monitor sees everyone's:
.show queries | where Text has "PlantTelemetry" | summarize queries = count(), last_query = max(StartedOn) by User, Application
A table with one reader, a dashboard service account, needs one-minute aggregates, not three years of 1 Hz data in the hot cache.
The objection: storage is cheap, keep every reading
The strongest case against all this: $388 a month is small next to a plant's budget, and raw readings you deleted cannot be recomputed when a quality investigation or a model needs them.
Half of it holds. Keep the raw readings; the lifecycle rule above keeps all 18.7 TB for $43 a month. The money is in where the readings sit, not in whether they exist. The objection loses where "keep everything" means keeping it in the ADX hot cache, which turns a retention habit into engine nodes, and where three copies of the same signal are billed by three teams who each assume another one owns it.
What this model does not tell you
- List price, read October 28, 2026, East US. Reserved capacity, enterprise agreements and other regions change every row.
- The plant is hypothetical. Tag counts, sampling rates and record sizes vary by line; 100 bytes of JSON per reading is an assumption, and Avro or JSON encoding in storage adds overhead on top of the payload.
- The ADX figure is a floor. It leaves out the data management nodes, ADX's own storage, networking, and any scale-out a long hot cache would force. Microsoft's cost estimator sizes a real cluster.
- Storage is billed on data held at month end, with no read, write or rehydration costs. Reading archived data back is charged separately.
- Not covered: Device Provisioning Service, Event Hubs as a custom endpoint, Microsoft Fabric and Azure IoT Operations.
For the trend behind these numbers, see the Industry 4.0 data explosion. For the waste nobody owns across a data platform, see cloud waste in data infrastructure.
Where Datapace fits
A plant's sensor bill is split across a hub, a storage account, an ADX cluster and often an on-site historian, and none of them says which readings anyone reads. Datapace is building one map of your data estate (databases, warehouses, pipelines and what consumes them) with usage and cost attached, and agents that propose changes as pull requests your team reviews and merges. If the pipeline after the hub is where your bill hides, start with data pipeline cost.
Sources
- Microsoft, Azure Retail Prices API: IoT Hub, East US, Blob Storage, East US and E2d v5, East US.
- Microsoft, Azure IoT Hub pricing and Azure Data Explorer pricing.
- Microsoft Learn, Azure IoT Hub billing information, IoT Hub quotas and throttling, Choose the right IoT Hub tier and size, IoT Hub endpoints, Troubleshoot IoT Hub error codes and Monitoring data reference.
- Microsoft Learn, Access tiers for blob data and Lifecycle policies for access tiers.
- Microsoft Learn, Select a SKU for your Azure Data Explorer cluster, Retention policy, Caching policy, .show queries and Cost estimator.
- Microsoft Learn, az monitor metrics.




