
Operations
Zabbix vs Prometheus for SNMP: Monitoring the Network You Own
Zabbix as a network monitoring tool: agent vs SNMP polling, traps via snmptrapd, templates and proxy groups, and where a Prometheus snmp_exporter stack fits.
Most Zabbix-versus-Prometheus comparisons are feature tables: native SNMP against PromQL, a configuration UI against YAML. None of that helps decide how a rack of switches, UPSes, PDUs and baseboard management controllers gets watched for the next ten years. That turns on mechanics — who opens the connection, where vendor MIB knowledge is encoded, what happens when a site's WAN goes dark, and how a dead switch stops paging you forty-eight times. This article walks them as of 22 October 2026, against Zabbix 7.0 LTS and Prometheus 3.15.
The hardware nobody exports metrics from
The cloud-native stack assumes the watched thing can run an exporter or speak OpenTelemetry. Much of a self-hosted estate cannot. A top-of-rack switch runs vendor firmware and nothing else; a UPS, a metered PDU, a storage appliance, the BMC in every server expose SNMP and little more. Their failures take everything above them down: a PDU breaker, a failing fan tray, a transceiver throwing errors before a link drops.
If your estate is Kubernetes on rented compute, the OpenTelemetry, Prometheus and Loki stack covers it. If you own the racks, the device layer is a first-class monitoring problem, and the tool you pick decides who carries the vendor knowledge.
Two collection models: host objects versus scraped series
Zabbix is built around objects in a database. A host has interfaces (agent, SNMP, IPMI, JMX); items define what to collect; triggers are expressions over item history; templates bundle items, triggers and discovery rules so a hundred switches of one family share one definition. Configuration lives in the SQL database, edited through the frontend or API; the server or its proxies collect.
Prometheus is built around labelled time series. Its overview states the core mechanism: time series collection happens via a pull model over HTTP. For SNMP devices, the endpoint it scrapes is snmp_exporter, which the project describes as the recommended way to expose SNMP data in a format Prometheus can ingest. The exporter, in the README's words, is meant to run on a few central machines and can be thought of like a "Prometheus proxy": Prometheus asks it to walk a target, it walks the device, and it returns the result as metrics.
In Zabbix, a device is a row with an identity, a template and a history. In Prometheus, it is a value of the instance label that exists while a scrape config names it. Zabbix carries state about what should exist; Prometheus carries series about what was observed. That placement of the device model is the decision you are actually making.
Agent, SNMP and traps: Zabbix's three paths into a device
Agent checks: passive, active, and the firewall
For servers that can run software, the Zabbix agent documentation defines two modes. In a passive check the agent responds to a request from the Zabbix server or proxy. In an active check the agent collects and sends data without waiting for a request. The agent listens on port 10050 by default. So the choice is about network direction: passive needs inbound reachability to every agent, active only outbound. Zabbix's own active/passive appendix suggests that an agent behind a firewall may use only active checks, because then the firewall need not allow incoming connections. Agent 2 changes internals, not the model: its metrics come from plugins, and checks from different plugins can run concurrently.
SNMP polling: walk[] and get[]
For devices that speak only SNMP, Zabbix 7.0 has two item keys documented on the SNMP item page: walk[OID1,OID2,...] retrieves a subtree, get[OID] retrieves a single value, both asynchronously, and the docs recommend them over legacy single-OID items for better performance. Bulk requests use GetBulk on SNMPv2 and v3 interfaces and GetNext on SNMPv1, with max repetitions set per interface.
The pattern that makes this scale is low-level discovery on top of a walk. The SNMP walk discovery example shows a single walk[] item that performs one table walk and returns every entry in one request; "SNMP walk to JSON" preprocessing turns it into discovery data, and dependent item prototypes such as net.if.in[{#SNMPINDEX}] are created per interface. And because the LLD documentation lets entities that are no longer discovered be disabled or deleted automatically, a decommissioned line card does not leave a graveyard of dead items behind.
Traps: snmptrapd writes, Zabbix reads
Polling notices a slow fan on the next cycle; a trap arrives when the device decides. The Zabbix SNMP trap page describes the design: traps are received by snmptrapd, passed to Zabbix through a Bash or Perl receiver or SNMPTT, written to a file, and read by the server or proxy once StartSNMPTrapper=1 and SNMPTrapperFile are set. On the Zabbix side, snmptrap[regexp] items catch matching traps and snmptrap.fallback catches every trap on that interface no other snmptrap[] item matched — alert on it first, since an unmatched trap is something your templates did not anticipate.
This script checks SNMPv3 polling and writes an snmptrapd.conf for the Bash receiver using the Zabbix 7.0 trap page's directives, with secrets from the environment.
#!/usr/bin/env bash
# Check SNMPv3 polling, then point snmptrapd at the Zabbix Bash receiver.
# Run as root on the proxy host.
set -euo pipefail
DEVICE="edge-sw-01.example.internal"
SNMP_USER="zbx-poll"
TRAP_USER="zbx-trap"
TRAP_ENGINE_ID="0x8000000001020304" # the sending device's engine ID
: "${SNMP_AUTH_PASS:?set SNMP_AUTH_PASS}"
: "${SNMP_PRIV_PASS:?set SNMP_PRIV_PASS}"
: "${TRAP_AUTH_PASS:?set TRAP_AUTH_PASS}"
: "${TRAP_PRIV_PASS:?set TRAP_PRIV_PASS}"
# 1. Polling path: walk interface names over SNMPv3 with auth and privacy.
# -A/-X expose secrets in the process list; one-off checks only.
snmpwalk -v3 -l authPriv \
-u "$SNMP_USER" -a SHA -A "$SNMP_AUTH_PASS" -x AES -X "$SNMP_PRIV_PASS" \
"$DEVICE" IF-MIB::ifName
# 2. Trap path: accept SNMPv3 traps from one USM user and execute the receiver.
mkdir -p /var/lib/zabbix/snmptraps
umask 077
cat > /etc/snmp/snmptrapd.conf <<EOF
createUser -e ${TRAP_ENGINE_ID} ${TRAP_USER} SHA ${TRAP_AUTH_PASS} AES ${TRAP_PRIV_PASS}
authUser log,execute ${TRAP_USER}
traphandle default /bin/bash /usr/sbin/zabbix_trap_handler.sh
EOF
systemctl restart snmptrapd
The Prometheus path: snmp_exporter, MIBs and a generator you build
The Prometheus route has two halves. The exporter (0.30.1, released 6 January 2026, is the latest as of this writing) runs centrally and walks devices when scraped. Its configuration, snmp.yml, is — per the README — not meant to be edited by hand. It is produced by the generator, which reads generator.yml, uses NetSNMP to parse the vendor MIBs you supply, and writes snmp.yml. Because of that dynamic NetSNMP dependency, the README says you must build the generator yourself. So a small build pipeline and a MIB collection become part of your monitoring estate.
A minimal generator.yml for interfaces walks the IF-MIB tables and turns ifIndex into readable labels. It deliberately carries no credentials:
# generator.yml — input to the snmp_exporter generator (not read by the exporter)
modules:
if_mib:
walk:
- sysUpTime
- ifTable
- ifXTable
lookups:
- source_indexes: [ifIndex]
lookup: ifName
- source_indexes: [ifIndex]
lookup: ifAlias
Credentials go in a second, auths-only file. Per the README, --config.file can be repeated, and --config.expand-environment-variables expands environment variables into username, password and priv_password only, erroring at load if one is missing. Duplicate auth or module names across files are rejected, so keep each name in exactly one file:
# auth.yml — loaded with:
# snmp_exporter --config.file=snmp.yml --config.file=auth.yml \
# --config.expand-environment-variables
auths:
site_v3:
version: 3
security_level: authPriv
username: ${SNMP_USERNAME}
password: ${SNMP_AUTH_PASSWORD}
auth_protocol: SHA256
priv_protocol: AES
priv_password: ${SNMP_PRIV_PASSWORD}
Prometheus then uses the documented multi-target relabelling pattern: each device address becomes the target parameter and the instance label, and the scrape is redirected to the exporter. A second job scrapes the exporter itself, which matters for alerting.
# prometheus.yml
global:
scrape_interval: 60s
rule_files:
- /etc/prometheus/rules/snmp.yml
scrape_configs:
- job_name: snmp
metrics_path: /snmp
params:
auth: [site_v3]
module: [if_mib]
static_configs:
- targets: [edge-sw-01.example.internal, edge-sw-02.example.internal]
labels:
site: dc1
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: snmp-exporter.dc1.example.internal:9116
- job_name: snmp_exporter
static_configs:
- targets: [snmp-exporter.dc1.example.internal:9116]
labels:
site: dc1
Note what is absent: nothing in this pipeline listens for traps. Trap reception on the Prometheus side is a separate component you design, operate and route into Alertmanager yourself — count it in the comparison if traps matter.
Templates at scale: where device knowledge lives
Every network monitoring system encodes vendor knowledge somewhere — which OIDs hold fan state, which interfaces deserve alerts. In Zabbix it lives in templates. Zabbix ships out-of-the-box templates for many network device families, covering — where the device exposes them — chassis faults (power supplies, fans, temperature), CPU and memory, inventory, and interface monitoring through IF-MIB and EtherLike-MIB. Templates you customise can be exported in the default YAML format, with XML and JSON also available, including linked templates, items, triggers and discovery rules with their prototypes.
The sustainable discipline is treating exported YAML as source: export after every change, commit, review the diff, import into staging before production. The database stays the runtime truth; git becomes the record of intent — the split the Puppet versus Ansible article draws between a control plane and the repository that feeds it.
On the Prometheus side, the equivalent knowledge lives in generator modules, the MIBs they resolve against, and the alert rules written over the resulting metric names. The README says the default snmp.yml covers a variety of common hardware; vendor-specific health tables beyond that, and the alert rules over them, are yours to write. So the question is ownership: Zabbix concentrates device knowledge in templates a team can curate in a UI; Prometheus spreads it across YAML, MIBs and PromQL, which suits teams that already review everything as code.
Alert routing: escalations, inhibition and the silence of a dead device
A core switch dies and forty-eight interface alerts page alongside it. Both systems solve this, differently.
Zabbix handles it in the data model: triggers can be made dependent on a parent device's availability trigger, and actions with escalation steps decide who hears about what remains. Each escalation step lasts at least 60 seconds, and the number of steps is not limited. Silence detection uses nodata(); the history functions reference gives two caveats: the history syncer evaluates it only every 30 seconds, so shorter periods are meaningless, and for hosts monitored by a proxy, nodata triggers are by default sensitive to proxy availability — so a dead WAN link does not fire every device's no-data trigger at once.
Prometheus splits the work between rules and Alertmanager, which deduplicates, groups and routes alerts and handles silencing and inhibition — suppressing notifications for some alerts while others are already firing. The subtlety in the multi-target pattern is what up means: for the snmp job, up reflects the scrape of the exporter on behalf of that device, so an exporter outage makes every device look down. The rules below therefore alert on the exporter separately, and use absent() — which returns a one-element vector when its input is empty — against the exporter's own series, the one that actually disappears when the exporter job vanishes.
# /etc/prometheus/rules/snmp.yml
groups:
- name: snmp-devices
rules:
- alert: SnmpExporterDown
expr: up{job="snmp_exporter"} == 0
for: 2m
labels:
severity: critical
- alert: SnmpExporterAbsent
expr: absent(up{job="snmp_exporter"})
for: 5m
labels:
severity: critical
site: dc1
- alert: DeviceDown
expr: up{job="snmp"} == 0
for: 5m
labels:
severity: critical
- alert: InterfaceDown
expr: ifOperStatus{job="snmp"} == 2 and on (instance, ifIndex) ifAdminStatus{job="snmp"} == 1
for: 5m
labels:
severity: warning
# alertmanager.yml
route:
receiver: network-oncall
group_by: [alertname, site]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receivers:
- name: network-oncall
webhook_configs:
- url: https://alerts.example.com/hooks/network
inhibit_rules:
- source_matchers: [alertname="DeviceDown"]
target_matchers: [alertname="InterfaceDown"]
equal: [instance]
- source_matchers: [alertname=~"SnmpExporterDown|SnmpExporterAbsent"]
target_matchers: [alertname=~"DeviceDown|InterfaceDown"]
equal: [site]
Zabbix encodes dependency in its host and trigger model; Prometheus encodes it in labels and inhibition rules you keep consistent with scrape configs by hand.
Failure modes: proxies, buffers and the database you now run
The Zabbix proxy documentation states that all data collected by a proxy is stored locally before being transmitted to the server, and ProxyOfflineBuffer sets how many hours the proxy keeps data while it cannot reach the server. That durability depends on the buffer mode. The proxy configuration appendix lists ProxyBufferMode as disk by default, hybrid, or memory — and in memory mode, old data is discarded when the buffer runs out of memory and the buffer is discarded on shutdown. Pick memory mode only if a history gap during a WAN outage is acceptable.
# excerpt — zabbix_proxy.conf for a site proxy (other required settings omitted)
Server=zabbix.example.internal
Hostname=proxy-dc1
ProxyBufferMode=disk
ProxyOfflineBuffer=24
StartSNMPTrapper=1
SNMPTrapperFile=/var/lib/zabbix/snmptraps/snmptraps.log
Zabbix 7.0 also added proxy groups: when a proxy in a group goes offline, its hosts are immediately redistributed to the other proxies. The server tier has its own high-availability mode, with one active node and the others on standby, ready to take over. Neither removes the SQL database underneath.
The real operational cost is that database. The history and trends page explains that history keeps every collected value while trends keep hourly aggregates, the housekeeper removes old data, and the general strong advice is to keep history for as few days as possible. TimescaleDB is supported for the server database but, per its install page, not for the proxy.
Prometheus fails differently. Its storage documentation says local retention defaults to 15 days if no retention flag is set, and that local storage is not clustered or replicated. Long retention and redundancy therefore mean paired servers or remote storage you choose and run.
Security and audit: SNMPv3, credentials and evidence
The snmp_exporter README states the baseline plainly: community strings are not secrets, because SNMP v1 and v2c send them unencrypted, and secure access requires SNMPv3. Zabbix supports all three SNMPv3 security levels — noAuthNoPriv, authNoPriv and authPriv — and only the last gives both authentication and privacy. Across any segment you do not fully control, authPriv is the floor.
In Zabbix, SNMP credentials sit in host interface settings and therefore in the database and its backups; the Prometheus pattern above keeps them in the exporter's environment. Either way the collection tier holds read credentials to every device, so treat the proxy or exporter host like a jump host. Correlating device events with other logs also depends on trusted time across the estate, and trap and alert streams belong in the same self-operated SIEM pipeline as the rest of your audit evidence.
Licensing is the other audit question. Per the Zabbix licence page, versions up to 6.4 were released under GPLv2, and from 7.0 every release is AGPLv3. The licence FAQ frames the purpose: copyleft for modified versions made available over a network. The FAQ states the obligation in those terms: users must share source code if they modify Zabbix and make it available to others, by distribution or over a network. Run it unmodified and internally, and that obligation does not arise; patch it and expose it to customers, and it does.
Exit ramps: leaving either one without losing the estate
- Out of Zabbix: template YAML exports in git are a readable inventory of items, triggers and discovery rules — the specification any replacement must meet.
- Into Zabbix from Prometheus-format sources: Zabbix can ingest Prometheus-format endpoints with an HTTP master item and dependent items using Prometheus pattern or Prometheus to JSON preprocessing. Any exporter you already run is a valid Zabbix data source.
- Out of the Prometheus path:
generator.yml, the MIBs and the rule files are plain text; OID lists and thresholds carry over. - Dashboards over both: Grafana Labs lists a Zabbix data source plugin, so one dashboard layer can read both stores during a migration or permanently.
The practical exit is overlap: run both against a subset of devices, compare alerts, then move one device family at a time — a one-step cutover finds out too late what the old system caught that nobody wrote down. The observability exit-cost analysis makes the same point about SaaS vendors; self-hosted tools lower the price of leaving but do not remove the work.
The long game: support windows and who is on call
Per the Zabbix lifecycle page as read on 22 October 2026, LTS releases get five years — three of full support and two of limited support. Zabbix 7.0 LTS was released on 4 June 2024, with full support until 30 June 2027 and limited support until 30 June 2029. The newest supported release is 7.4, from 1 July 2025, and 8.0 LTS is listed as planned for Q4 2026. Start greenfield work on 7.0 LTS and plan the 8.0 upgrade once it ships, not before. Prometheus releases more often — 3.15.1 shipped on 21 October 2026 — and you own the upgrade cadence for it and every exporter.
The decision rule that survives a decade:
- Do the devices matter through traps? If chassis and power events arrive as traps and you need them, Zabbix's snmptrapd path is documented end to end; with Prometheus it is a component you add.
- Devices or services? Devices with vendor templates favour Zabbix's object model; services exposing metrics favour Prometheus.
- Who is on call for collection? A network team curating templates in a UI, or a platform team reviewing YAML and PromQL in pull requests. Give the tool to the people who will carry it.
Landing on both — Zabbix for the racks, Prometheus for what runs in them, joined by the bridges above — is not indecision. It puts each kind of knowledge where its owners can keep it.
§FAQ/Common questions
Frequently asked
Is Zabbix or Prometheus better for SNMP network monitoring?
Neither in general. Zabbix polls SNMP natively with walk[] and get[] items, receives traps through snmptrapd, ships network device templates and buffers data at site proxies. Prometheus uses snmp_exporter, which walks devices when scraped using a snmp.yml generated from MIBs, and has no trap receiver in that pipeline. Choose on traps, device mix and who owns the collection tier.
Should Zabbix agents use active or passive checks?
Passive checks need the server or proxy to reach the agent, by default on port 10050. Active checks have the agent send data without being asked, so no inbound connection to the agent is needed. Zabbix's documentation suggests active-only checks for agents behind a firewall.
How does Zabbix receive SNMP traps?
snmptrapd receives the trap and passes it to a Bash or Perl receiver, or SNMPTT, which writes it to a file. The Zabbix server or proxy reads that file when StartSNMPTrapper=1 and SNMPTrapperFile are set. snmptrap[regexp] items match specific traps, and snmptrap.fallback catches anything no other trap item matched on that interface.
Does a Zabbix proxy keep data when the WAN link drops?
Yes with the default disk buffer mode, and with hybrid mode: the proxy stores collected data locally and keeps it for ProxyOfflineBuffer hours while it cannot reach the server. In memory mode the buffer is discarded on shutdown and old data is dropped when memory runs out. In 7.0, proxy groups also move a failed proxy's hosts to other proxies.
What licence is Zabbix released under?
Zabbix 7.0 and later are released under AGPLv3; versions up to 6.4 were GPLv2. The AGPL's obligations apply to modified versions made available to others, including over a network, so the source-sharing duty arises when you modify Zabbix and make it available to others.
Executive Briefing
Thirty minutes to clarify your infrastructure risk
Walk us through your vendor footprint and regulatory constraints. We will tell you honestly where sovereignty creates leverage — and where it does not. No pitch deck. No obligation.