MTBF MTTR calculation is the foundation of every reliability conversation in a plant: how often does this machine fail, and how long does it take us to get it running again? This guide explains both formulas, works through a complete example, highlights the definition traps that make numbers incomparable, and shows how to calculate the metrics automatically from failure and repair events captured over MQTT.
What MTBF and MTTR Measure
MTBF (Mean Time Between Failures) is the average operating time between one failure and the next for a repairable asset. Higher is better. It describes reliability: how long the machine typically runs before something breaks.
MTTR (Mean Time To Repair) is the average time from the moment a failure stops the machine until it is restored to service. Lower is better. It describes maintainability and the effectiveness of your response: detection, travel, diagnosis, waiting for parts, repair and testing.
Together they determine how much of the time a machine is available, and they point to different improvement levers. Low MTBF calls for better maintenance strategy, design changes or condition monitoring. High MTTR calls for faster detection, better spare parts management, clearer procedures and training.
The Formulas
| Metric | Formula | Unit |
|---|---|---|
| MTBF | Total operating time / Number of failures | hours |
| MTTR | Total repair (downtime) time / Number of repairs | hours or minutes |
| Failure rate | Number of failures / Total operating time (= 1 / MTBF) | failures per hour |
| Inherent availability | MTBF / (MTBF + MTTR) | percent |
Operating time means the time the asset was supposed to run and actually ran. It excludes planned downtime such as weekends, planned maintenance and changeovers, and it excludes the failure downtime itself. Getting this denominator right is where most calculations go wrong.
Worked MTBF MTTR Calculation Example
Take a packaging machine over a four-week period. It is scheduled for two shifts of 8 hours, five days a week, which gives 20 days x 16 hours = 320 scheduled hours. During that period it records four failures:
| Failure | Cause | Downtime |
|---|---|---|
| 1 | Jammed infeed | 0.5 h |
| 2 | Broken drive belt | 3.0 h |
| 3 | Sensor misalignment | 1.0 h |
| 4 | Jammed infeed | 1.5 h |
Step by step:
- Total downtime from failures = 0.5 + 3.0 + 1.0 + 1.5 = 6.0 hours.
- Operating time = 320 scheduled hours - 6.0 hours of failure downtime = 314 hours.
- MTBF = 314 / 4 = 78.5 hours.
- MTTR = 6.0 / 4 = 1.5 hours.
- Inherent availability = 78.5 / (78.5 + 1.5) = 98.1 percent.
- Failure rate = 4 / 314 = about 0.0127 failures per operating hour.
The same data also tells you where to look. Two of the four failures were infeed jams, so a single fix there could halve the failure count, while the belt failure dominates MTTR and suggests checking whether spare belts are stocked at the line.
Definition Traps to Avoid
Metrics are only useful if everyone calculates them the same way. Agree on these rules before you publish a single number:
- What counts as a failure. A common rule is any unplanned stop longer than a threshold, for example five minutes, that requires intervention. Micro-stops below the threshold belong in performance loss, not MTBF. Write the threshold down.
- Operating time versus calendar time. Using calendar hours inflates MTBF for machines that only run one shift. Use scheduled run time minus failure downtime.
- Where MTTR starts and stops. Start at the moment the machine stopped, not when the technician arrived. Stop when the machine is released back to production, not when the work order is closed in the office. Response time is part of the problem you are trying to measure.
- MTBF versus MTTF. MTTF (Mean Time To Failure) applies to non-repairable items such as a light bulb or a sealed bearing. For machines you repair, use MTBF.
- Small samples. With two failures a year, MTBF swings wildly. Report it with the number of failures, and use longer windows for very reliable assets.
- MTBF is not a lifetime. An MTBF of 1,000 hours does not mean the machine runs 1,000 hours and then breaks. It is an average rate; failures can and do happen early.
Why Manual Tracking Fails
In many plants MTBF and MTTR are calculated once a month from CMMS work orders. That introduces three problems. Work orders are created late, so the recorded failure start is wrong. Short failures fixed by operators never get a work order at all, so failure counts are too low. And by the time the monthly report arrives, the pattern that caused the failures is weeks old.
Capturing failure and repair events directly from the machine and the people who fix it solves all three. The machine knows exactly when it stopped and restarted. An operator panel, a digital andon system or a technician's phone can add the reason. MQTT is a natural transport for those events, because the same events also feed machine downtime tracking and OEE dashboards.
Event Design for Automatic Tracking
Use one topic per asset for maintenance events, and a small set of event types:
acme/plant1/packaging/line2/cartoner1/maintenance/event
{"event": "failure_start", "ts": "2026-10-16T08:12:40Z", "reason": "infeed_jam", "id": "f-0193"}
{"event": "repair_end", "ts": "2026-10-16T08:41:05Z", "id": "f-0193", "technician": "T07"}
{"event": "planned_stop_start", "ts": "2026-10-16T14:00:00Z"}
{"event": "planned_stop_end", "ts": "2026-10-16T14:30:00Z"}
Publish these events with QoS 1 so they are delivered at least once, and give each failure an ID so a duplicate delivery does not count twice. As the guide to MQTT QoS levels explains, QoS 1 is the right trade-off for event data like this.
Calculating MTBF and MTTR from MQTT Events
The Python service below subscribes to maintenance events for all assets under a prefix, stores them in SQLite, and every minute recalculates MTBF and MTTR over a rolling 30-day window. It publishes the results as retained messages so any dashboard sees current values the moment it subscribes. It uses paho-mqtt 2.x and the ConnectMQ public test broker; replace the prefix with your own.
import json
import sqlite3
import time
from datetime import datetime, timedelta, timezone
import paho.mqtt.client as mqtt
PREFIX = "connectmq/demo/d27e5b"
WINDOW_DAYS = 30
db = sqlite3.connect("maintenance.db", check_same_thread=False)
db.execute("""CREATE TABLE IF NOT EXISTS events (
asset TEXT, event TEXT, ts TEXT, fid TEXT,
UNIQUE(asset, event, ts))""")
def parse(ts):
return datetime.fromisoformat(ts.replace("Z", "+00:00"))
def on_connect(client, userdata, flags, reason_code, properties):
client.subscribe(f"{PREFIX}/+/maintenance/event", qos=1)
def on_message(client, userdata, msg):
asset = msg.topic.split("/")[3]
e = json.loads(msg.payload)
db.execute("INSERT OR IGNORE INTO events VALUES (?,?,?,?)",
(asset, e["event"], e["ts"], e.get("id")))
db.commit()
def metrics(asset, now):
start = now - timedelta(days=WINDOW_DAYS)
rows = db.execute("SELECT event, ts FROM events WHERE asset=? ORDER BY ts", (asset,)).fetchall()
failures, repair_s, planned_s = 0, 0.0, 0.0
open_fail = open_plan = None
for event, ts in rows:
t = max(parse(ts), start)
if event == "failure_start":
open_fail = t
if parse(ts) >= start:
failures += 1
elif event == "repair_end" and open_fail:
repair_s += (t - open_fail).total_seconds()
open_fail = None
elif event == "planned_stop_start":
open_plan = t
elif event == "planned_stop_end" and open_plan:
planned_s += (t - open_plan).total_seconds()
open_plan = None
if open_fail:
repair_s += (now - open_fail).total_seconds()
operating_h = (WINDOW_DAYS * 86400 - planned_s - repair_s) / 3600
mtbf = operating_h / failures if failures else None
mttr = repair_s / 3600 / failures if failures else None
avail = mtbf / (mtbf + mttr) if failures else 1.0
return {"window_days": WINDOW_DAYS, "failures": failures,
"operating_h": round(operating_h, 1),
"mtbf_h": round(mtbf, 1) if mtbf else None,
"mttr_h": round(mttr, 2) if mttr else None,
"inherent_availability": round(avail, 4)}
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="reliability-d27e5b")
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_start()
while True:
time.sleep(60)
now = datetime.now(timezone.utc)
for (asset,) in db.execute("SELECT DISTINCT asset FROM events").fetchall():
result = metrics(asset, now)
client.publish(f"{PREFIX}/{asset}/maintenance/kpi", json.dumps(result), qos=1, retain=True)
print(asset, result)
Simulate a failure from the command line and watch the KPI update within a minute:
mosquitto_pub -h broker.connectmq.com -p 1883 -i sim-d27e5b -q 1 \
-t "connectmq/demo/d27e5b/cartoner1/maintenance/event" \
-m '{"event":"failure_start","ts":"2026-10-16T08:12:40Z","id":"f-0001"}'
mosquitto_pub -h broker.connectmq.com -p 1883 -i sim-d27e5b -q 1 \
-t "connectmq/demo/d27e5b/cartoner1/maintenance/event" \
-m '{"event":"repair_end","ts":"2026-10-16T08:41:05Z","id":"f-0001"}'
This example treats all time outside planned stops and repairs as operating time, which suits continuously running assets. For machines that run only some shifts, publish planned_stop_start and planned_stop_end for non-production periods, or feed the shift calendar from your MES. The broker only transports events; the SQLite file (or your historian) is the system of record, because a broker is not a database. In production, point the service at your private ConnectMQ broker with the username, password and client ID generated in the portal, and use TLS on port 8883.
Using the Numbers
- Rank assets by failure count first, then by MTTR. The asset with many short failures needs a reliability fix; the one with few long failures needs a maintainability fix.
- Split by reason code. MTBF per failure reason shows which fixes would move the metric most.
- Track trends, not snapshots. A rolling 30- or 90-day MTBF that rises after you introduce condition monitoring is the clearest proof that condition monitoring vs predictive maintenance investments are paying off.
- Watch MTTR components. If detection is slow, add alerts; if parts are slow, review spares; if diagnosis is slow, improve procedures.
For the bigger picture of plant metrics and how reliability connects to OEE, see the smart manufacturing guide.
Track Reliability KPIs with ConnectMQ
ConnectMQ is a hosted MQTT broker with MQTT 5, QoS 1 and 2, retained messages, TLS and a live topic explorer, so failure events, repair events and calculated KPIs all flow through one private backbone. Create your broker on the free Serverless plan at app.connectmq.com, no credit card required, or test first on the public MQTT test broker.
Frequently Asked Questions
How do you calculate MTBF?
Divide total operating time by the number of failures in the same period. Operating time excludes planned downtime and the downtime caused by the failures themselves.
How do you calculate MTTR?
Divide the total time spent restoring failed equipment by the number of repairs. Measure from the moment the machine stopped until it is released back to production.
What is the relationship between MTBF, MTTR and availability?
Inherent availability equals MTBF divided by the sum of MTBF and MTTR. Raising MTBF or lowering MTTR both improve availability.
What is the difference between MTBF and MTTF?
MTBF applies to repairable assets that return to service after a failure. MTTF applies to non-repairable items that are replaced when they fail.



