Industrial IoT

MQTT for Oil and Gas Remote Monitoring Over Cellular and Satellite

How to use MQTT for wellheads, pipelines and tank batteries over cellular and satellite links, with keep alive, session, QoS and report-by-exception settings tuned for expensive, intermittent connections.

Remote wellhead with a solar-powered RTU sending data over a satellite link to a cloud broker, illustrating MQTT oil and gas monitoring
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

MQTT oil and gas deployments have become a standard way to monitor wellheads, pipelines, compressor stations and tank batteries that sit far from any fiber. Its report-by-exception model, small packets and tolerance of unreliable links match the realities of cellular and satellite backhaul. In this guide you will learn how to architect remote monitoring with MQTT, which keep alive, session and QoS settings work on expensive links, and how to build an edge publisher that keeps bandwidth low without losing important events.

Why Remote Oil and Gas Assets Suit MQTT

Upstream and midstream assets share a set of constraints that make traditional polling painful:

  • Expensive or limited bandwidth. Satellite and some cellular plans bill by the byte or have tight data caps. Polling unchanged values every few seconds wastes money.
  • High latency. Geostationary satellite round trips are long, so a master that polls hundreds of sites sequentially ends up with very slow scan cycles.
  • Intermittent connectivity. Weather, power and coverage cause outages that the telemetry system must survive without losing alarms.
  • Power budgets. Solar-powered RTUs and gateways want the radio idle as much as possible.
  • Security exposure. Remote sites are physically accessible and connect over public networks.

MQTT addresses these directly. Field devices open one outbound TLS connection and keep it, publish only meaningful changes, and let the broker distribute data to SCADA, historians and analytics. The MQTT in SCADA systems guide explains this shift from polling in more depth.

Reference Architecture

A typical MQTT oil and gas architecture has four layers:

  1. Field instruments and controllers. Flow computers, pressure and temperature transmitters, tank level radar, pump controllers, ESD systems, usually speaking Modbus or a vendor protocol locally.
  2. Edge gateway or RTU. Reads local devices, applies deadbands, timestamps values, buffers during outages and publishes MQTT. Often Sparkplug B for SCADA compatibility.
  3. Backhaul. Cellular (LTE, LTE-M), licensed or unlicensed radio, or satellite (geostationary or low-earth-orbit).
  4. Broker and consumers. A central broker, with SCADA hosts, historians, production accounting and leak detection systems as subscribers.

Keep safety functions local. Emergency shutdown and pressure protection must never depend on the link or the broker; MQTT carries monitoring data and, where approved, supervisory commands only.

The default settings of most MQTT libraries assume a LAN. On remote links, a few parameters make the difference between a reliable system and a noisy, expensive one.

Setting LAN default Remote-link guidance Why
Keep alive 60 s 60 to 300 s, but below the carrier NAT idle timeout Each PINGREQ costs bytes; too long and NAT silently drops the TCP session
Session Clean session Persistent session (MQTT 5: clean start false plus session expiry) Subscriptions and queued QoS 1 messages survive short outages
QoS for telemetry 0 or 1 1 for events and alarms, 0 for high-rate values superseded by the next sample Balance delivery guarantees against acknowledgement overhead
Message expiry (MQTT 5) None Set on commands and short-lived data Prevents a stale setpoint from executing after a long outage
Payload format Verbose JSON Compact JSON with short keys, or Sparkplug B Protobuf Bytes matter on metered links
Publish strategy Fixed interval Report by exception plus a slow heartbeat Most values change rarely
Reconnect backoff Immediate Exponential with jitter Avoids reconnect storms after a network-wide outage

Keep alive and NAT timeouts

Cellular carriers put devices behind carrier-grade NAT, which drops idle TCP flows after a period the carrier decides. If your keep alive is longer than that, the connection dies silently and the device only finds out when its next publish fails. Measure it: start with 120 seconds, watch for unexplained reconnects in the broker connection log, and shorten until they stop. On satellite links, also allow for long round trips when choosing the client's ping timeout.

Report by exception for wellhead data

A tubing pressure that drifts by 0.1 percent does not need to cross a satellite. Set deadbands per tag from instrument accuracy and operational relevance, publish digital states and alarms on every change, and send a full refresh every 15 to 60 minutes as proof of life. The report-by-exception guide covers deadband selection, and store-and-forward for MQTT explains how to buffer and replay data across outages.

Example: A Bandwidth-Aware Edge Publisher

This Python publisher uses MQTT 5 with a persistent session, short JSON keys, per-tag deadbands, a heartbeat, message expiry on low-value data and exponential reconnect backoff. Replace read_instruments() with your Modbus or flow computer reads.

import json
import random
import time
import uuid

import paho.mqtt.client as mqtt
from paho.mqtt.packettypes import PacketTypes
from paho.mqtt.properties import Properties

# Public test broker for the lab: readable by everyone, so use simulated data only.
BROKER, PORT, USE_TLS = "broker.connectmq.com", 1883, False
USERNAME, PASSWORD = None, None                     # production: "YOUR_USERNAME", "YOUR_PASSWORD"
CLIENT_ID = f"wellpad-{uuid.uuid4().hex[:8]}"       # production: "YOUR_CLIENT_ID"
BASE = f"connectmq/demo/{uuid.uuid4().hex[:6]}/basin1/pad12/well3"

KEEPALIVE = 120
HEARTBEAT = 900                                     # full refresh every 15 minutes
DEADBANDS = {"tp": 2.0, "cp": 2.0, "ft": 0.5, "lv": 0.02}   # psi, psi, degF, m


def read_instruments():
    """Simulated values; replace with real Modbus or flow computer reads."""
    return {
        "tp": round(850 + random.uniform(-3, 3), 1),    # tubing pressure, psi
        "cp": round(420 + random.uniform(-3, 3), 1),    # casing pressure, psi
        "ft": round(96 + random.uniform(-1, 1), 1),     # flowline temperature, degF
        "lv": round(2.41 + random.uniform(-0.03, 0.03), 3),  # tank level, m
        "esd": False,                                   # ESD tripped
    }


def on_connect(client, userdata, flags, reason_code, properties):
    print("Connected:", reason_code, "session present:", flags.session_present)
    client.publish(f"{BASE}/st", "online", qos=1, retain=True)


def on_disconnect(client, userdata, flags, reason_code, properties):
    print("Disconnected:", reason_code)


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID,
                     protocol=mqtt.MQTTv5)
if USERNAME:
    client.username_pw_set(USERNAME, PASSWORD)
if USE_TLS:
    client.tls_set()
client.will_set(f"{BASE}/st", "offline", qos=1, retain=True)
client.reconnect_delay_set(min_delay=5, max_delay=300)   # exponential backoff
client.on_connect = on_connect
client.on_disconnect = on_disconnect

connect_props = Properties(PacketTypes.CONNECT)
connect_props.SessionExpiryInterval = 1800          # keep the session for 30 minutes
client.connect(BROKER, PORT, keepalive=KEEPALIVE, clean_start=False,
               properties=connect_props)
client.loop_start()

expiring = Properties(PacketTypes.PUBLISH)
expiring.MessageExpiryInterval = 3600               # analog values older than 1 h are useless

last, last_full = {}, 0.0
print("Publishing under", BASE)

while True:
    values = read_instruments()
    now = time.time()
    full = now - last_full >= HEARTBEAT
    changed = {}
    for key, value in values.items():
        if isinstance(value, bool):
            if full or value != last.get(key):
                # alarms and states: QoS 1, own topic, no expiry
                client.publish(f"{BASE}/alm/{key}", json.dumps(value), qos=1, retain=True)
                last[key] = value
        elif full or key not in last or abs(value - last[key]) >= DEADBANDS[key]:
            changed[key] = value
            last[key] = value
    if changed:
        changed["t"] = int(now)                     # epoch seconds: short and unambiguous
        client.publish(f"{BASE}/v", json.dumps(changed, separators=(",", ":")),
                       qos=1, properties=expiring)
    if full:
        last_full = now
    time.sleep(10)

A changed-values message looks like {"tp":853.4,"t":1792139421}, tens of bytes instead of a full snapshot every scan. Watch it from your desk:

mosquitto_sub -h broker.connectmq.com -p 1883 -i wellpad-watch-01 \
  -t 'connectmq/demo/+/basin1/#' -v

The free public MQTT broker keeps sessions for up to 30 minutes, which matches the session expiry above; production brokers on your own plan are where you tune it for your real outage profile.

Security for Remote Sites

Remote sites are exposed in ways plant-floor equipment is not. Apply these controls as a minimum:

  1. TLS on port 8883 for every connection over a public network, with certificate validation enabled.
  2. A unique username, password and client ID per site, so a stolen gateway can be revoked alone.
  3. Outbound-only connectivity; no inbound ports on the cellular modem or satellite terminal.
  4. Read-only by default. Remote commands such as choke changes need approval workflows, interlocks and message expiry.
  5. Hardened gateways: disabled unused services, secure boot where available, and physical tamper protection.
  6. Alerting on unexpected disconnects, which can indicate tampering as well as link problems.

Running the Broker

The central broker is the most important shared component, and it must be reachable from every site. ConnectMQ offers a fully managed MQTT service with MQTT 3.1.1 and 5.0, TLS, session expiry and message expiry, and per-client credentials. Its portal includes a live topic explorer, an ISA-95 devices view that groups sites and assets, and threshold alert rules, for example on tank level or casing pressure, with an alerts log for review. Edge gateways using Sparkplug B can be decoded and republished into readable ISA-95 topics for consumers that do not speak Sparkplug. For larger fleets, paid and dedicated plans raise connection counts and message sizes, and BYOC places the managed broker in your own cloud account.

For more on link choices and modem behavior, see MQTT over cellular, and for the wider architecture, the industrial IoT with MQTT guide.

Monitor Remote Assets with ConnectMQ

Start with one well pad or one compressor station. Create a free Serverless broker at app.connectmq.com, no credit card required, connect an edge gateway over TLS, and set your first threshold alert on a pressure or level. When the pilot proves out, scale on the same ConnectMQ cloud MQTT broker.

Frequently Asked Questions

Yes. MQTT's persistent connections, small headers and report-by-exception publishing suit high-latency satellite links. Tune keep alive, use persistent sessions and keep payloads compact.

What keep alive should I use on cellular?

Start around 120 seconds and keep it below the carrier's NAT idle timeout. If you see unexplained reconnects, shorten it.

Is Sparkplug B or JSON better for oil and gas telemetry?

Sparkplug B is more compact and integrates well with SCADA hosts. Short-key JSON is easier to inspect and works fine when payloads are small and changes are infrequent.

Should shutdown commands be sent over MQTT?

No. Safety functions must stay local and independent of the network. MQTT is suitable for monitoring and, with proper safeguards, supervisory commands.

Related articles

IIoT Edge Gateway: What It Does and How to Choose One

An IIoT edge gateway connects machines that speak Modbus, OPC UA or proprietary protocols to MQTT and the cloud. Learn its core roles, common architectures and how to choose the right one.

7 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.