Setting up a v3 user on the server-side agent for the default Linux snmpd
(net-snmp
package).
Out of scope: SNMP traps and read-write (rw) users.

SNMP version 3 allows packet transmission in encrypted form, making it safe to transfer telemetry over public networks without the risk of exposing either authentication information (analogous to a community string) or the data stream itself, which is encrypted using a symmetric algorithm with a shared key.
A Reminder: How v1/v2c Is Configured
In SNMP v1
/v2c
, the concept of a community
is used. This is essentially a passphrase that the agent receives from the client. If the community
matches access settings (for example, if the client’s IP address is within the allowed range), the agent returns the telemetry. Everything is transmitted in plaintext, including both the community
string and the requested telemetry.
Example requests in tcpdump (with community comminity_name
):
tcpdump: listening on br0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:28:09.382435 IP (tos 0x48, ttl 44, id 25108, offset 0, flags [DF], proto UDP (17), length 74)
192.158.1.38.46214 > 198.51.100.1.161: { SNMPv2c C="comminity_name" { GetNextRequest(25) R=1193096294 .1.3.6.1.2.1 } }
20:28:09.414940 IP (tos 0x48, ttl 44, id 25112, offset 0, flags [DF], proto UDP (17), length 77)
192.158.1.38.46214 > 198.51.100.1.161: { SNMPv2c C="comminity_name" { GetNextRequest(28) R=1193096295 .1.3.6.1.2.1.1.1.0 } }
20:28:09.447385 IP (tos 0x48, ttl 44, id 25117, offset 0, flags [DF], proto UDP (17), length 77)
192.158.1.38.46214 > 198.51.100.1.161: { SNMPv2c C="comminity_name" { GetNextRequest(28) R=1193096296 .1.3.6.1.2.1.1.2.0 } }
20:28:09.479880 IP (tos 0x48, ttl 44, id 25125, offset 0, flags [DF], proto UDP (17), length 77)
192.158.1.38.46214 > 198.51.100.1.161: { SNMPv2c C="comminity_name" { GetNextRequest(28) R=1193096297 .1.3.6.1.2.1.1.3.0 } }
20:28:09.512357 IP (tos 0x48, ttl 44, id 25128, offset 0, flags [DF], proto UDP (17), length 77)
...
NB: In tcpdump here and below, only requests are shown—responses are omitted.
To configure v2 community, add a line to /etc/snmp/snmpd.conf
with the following syntax:
rocommunity[6] communityname [access] [-V view]
Where:
6
(optional) – enables IPv6 (separate from IPv4)communityname
– the name of the community, effectively a shared passwordaccess
(optional) – access control options:default
,hostname
,network/bits
-V view
(optional) – limits visibility to a specific OID subtree (configured separately; out of scope here)
A basic example:
rocommunity comminity_name
rocommunity6 comminity_name
This sets up a single read-only community called comminity_name
for both IPv4 and IPv6 with no additional access restrictions.
That should be enough to understand the basics.
Authentication in SNMPv3
Version 3 drops the term community. Or rather, it’s been reworked, but the term itself is no longer used. Now there’s encryption for both the stream and the authentication data. What’s used instead?
A username
An authentication password
An encryption password
So instead of a familiar “login/password” pair, we get a less intuitive “login/two passwords” model. Each password also requires an associated algorithm:
The authentication password uses a hashing algorithm—traditionally MD5 or SHA (with SHA variants introduced in later versions)
The encryption password uses a symmetric encryption algorithm—traditionally DES or AES (again, later AES variants exist)
A sample v3
request in tcpdump looks like this:
tcpdump: listening on br0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
23:28:39.753314 IP (tos 0x48, ttl 44, id 62294, offset 0, flags [DF], proto UDP (17), length 92)
192.158.1.38.48116 > 198.51.100.1.161: { SNMPv3 { F=r } { USM B=0 T=0 U="" } { ScopedPDU E= C="" { GetRequest(14) R=30306933 } } }
23:28:39.785927 IP (tos 0x48, ttl 44, id 62301, offset 0, flags [DF], proto UDP (17), length 171)
192.158.1.38.48116 > 198.51.100.1.161: { SNMPv3 { F=apr } { USM B=9 T=330 U="user_name" } { ScopedPDU [!scoped PDU]8f_6f_9f_0a_aa_3b_69_8c_02_30_66_48_52_7d_52_2b_9e_b0_a2_84_cc_60_8a_9e_d5_67_30_52_26_88_0e_68_a7_89_5d_df_78_a4_9b_4e_62_dc_f6_54_f8_16_00_02_ba_f7} }
23:28:39.818831 IP (tos 0x48, ttl 44, id 62308, offset 0, flags [DF], proto UDP (17), length 174)
192.158.1.38.48116 > 198.51.100.1.161: { SNMPv3 { F=apr } { USM B=9 T=330 U="user_name" } { ScopedPDU [!scoped PDU]f1_46_7e_ec_3a_d4_38_94_69_38_14_73_20_71_de_1a_24_b2_61_56_d9_a2_c3_20_b2_6b_6e_11_5f_23_25_f7_56_ba_09_df_09_82_79_54_ec_22_7a_f5_81_60_52_59_83_65_40_09_ac} }
23:28:39.851664 IP (tos 0x48, ttl 44, id 62310, offset 0, flags [DF], proto UDP (17), length 174)
192.158.1.38.48116 > 198.51.100.1.161: { SNMPv3 { F=apr } { USM B=9 T=330 U="user_name" } { ScopedPDU [!scoped PDU]43_30_e9_c9_7c_e2_07_9e_41_74_53_98_51_79_ff_7b_26_51_93_b2_fe_35_db_8e_a4_67_58_87_3e_de_8c_f6_5a_3e_1d_a4_47_d7_3d_f9_c8_b1_ac_2f_d2_48_3a_57_d0_f4_a8_45_9c} }
23:28:39.884478 IP (tos 0x48, ttl 44, id 62316, offset 0, flags [DF], proto UDP (17), length 174)
192.158.1.38.48116 > 198.51.100.1.161: { SNMPv3 { F=apr } { USM B=9 T=330 U="user_name" } { ScopedPDU [!scoped PDU]a0_35_d4_83_cb_6a_82_f1_bd_d7_16_58_00_ff_d7_5e_03_3a_01_c8_be_2e_6d_e5_bf_eb_7c_ce_07_12_76_fc_ee_6e_61_dc_18_d3_4b_7e_dd_f7_bc_f1_3e_de_ad_52_a2_2e_22_ea_74} }
...
Note that the username is not encrypted, so be careful not to leak anything unnecessary in transit.
Configuration is a bit more involved. You can’t just drop a pre-written line into the config (with caveats), because authentication data is generated when the user is created. This complicates deployment using common tools like Ansible.
Both the agent and client must share the following (besides the agent hostname):
Username
Authentication password (CLI option
-a
for net-snmp)Authentication algorithm (
-A
)Encryption password (
-x
)Encryption algorithm (
-X
)
In addition to the main config /etc/snmp/snmpd.conf
, there are at least two other files for dynamic user creation and auth data storage:
/var/lib/snmp/snmpd.conf
/usr/share/snmp/snmpd.conf
The snmpd
daemon writes the necessary lines on startup. So before creating a user, the process must be stopped. If not, the built-in script will refuse to create a user, since it overwrites one of these files in-memory at startup.
To create a user on the agent, use:
net-snmp-create-v3-user -ro -a 'auth_pass' -A SHA -x 'priv_pass' -X AES user_name
This creates a read-only user named user_name
with:
auth_pass
(SHA)priv_pass
(AES)
The script writes lines to the two mentioned config files:
/var/lib/snmp/snmpd.conf
:
createUser user_name SHA "auth_pass" AES "priv_pass"
/usr/share/snmp/snmpd.conf
:
rouser user_name
But that’s not all. On startup, snmpd
modifies /var/lib/snmp/snmpd.conf
: all createUser
lines are removed and replaced with something like:
usmUser 1 3 0x80001f888052e226409c42d06300000000 "user_name" "user_name" NULL .1.3.6.1.6.3.10.1.1.3 0x018a3bb9c17caafed74347e50d918963e37e70d7 .1.3.6.1.6.3.10.1.2.4 0xcfdecd0e1bc6bf08eb7ae90e68bdb414 ""
The /usr/share/snmp/snmpd.conf
file remains unchanged. You can manage these usmUser
lines with the CLI utility snmpusm
(see man
).
SNMPv3 Security Levels
Let’s briefly touch on SNMPv3 security levels. Common levels include:
noAuthNoPriv
— no authentication, no encryptionauthNoPriv
— authenticated but unencryptedauthPriv
— authenticated and encrypted
The first is rarely used; let’s focus on authNoPriv
and authPriv
.
Sample tcpdump
output for authNoPriv
:
10:50:58.534839 IP (tos 0x48, ttl 44, id 54935, offset 0, flags [DF], proto UDP (17), length 92)
192.158.1.38.20723 > 198.51.100.1.161: { SNMPv3 { F=r } { USM B=0 T=0 U="" } { ScopedPDU E= C="" { GetRequest(14) R=1808634162 } } }
10:50:58.567563 IP (tos 0x48, ttl 44, id 54937, offset 0, flags [DF], proto UDP (17), length 162)
192.158.1.38.20723 > 198.51.100.1.161: { SNMPv3 { F=ar } { USM B=10 T=39805 U="user_name" } { ScopedPDU E=_80_00_1f_88_80_52_e2_26_40_9c_42_d0_63_00_00_00_00 C="" { GetNextRequest(25) R=1808634161 .1.3.6.1.2.1 } } }
10:50:58.600457 IP (tos 0x48, ttl 44, id 54945, offset 0, flags [DF], proto UDP (17), length 165)
192.158.1.38.20723 > 198.51.100.1.161: { SNMPv3 { F=ar } { USM B=10 T=39805 U="user_name" } { ScopedPDU E=_80_00_1f_88_80_52_e2_26_40_9c_42_d0_63_00_00_00_00 C="" { GetNextRequest(28) R=1808634163 .1.3.6.1.2.1.1.1.0 } } }
...
And for authPriv
:
10:51:47.463848 IP (tos 0x48, ttl 44, id 61280, offset 0, flags [DF], proto UDP (17), length 92)
192.158.1.38.54277 > 198.51.100.1.161: { SNMPv3 { F=r } { USM B=0 T=0 U="" } { ScopedPDU E= C="" { GetRequest(14) R=1901099838 } } }
10:51:47.496541 IP (tos 0x48, ttl 44, id 61282, offset 0, flags [DF], proto UDP (17), length 172)
192.158.1.38.54277 > 198.51.100.1.161: { SNMPv3 { F=apr } { USM B=10 T=39854 U="user_name" } { ScopedPDU [!scoped PDU]f2_87_ea_15_87_25_a7_b8_44_b4_38_62_15_86_d4_4e_1a_99_34_9e_6c_4d_6a_39_ea_1c_d7_1c_6e_f6_1f_76_c0_e2_ba_91_4d_8e_d5_9c_e7_06_29_c1_47_6e_a2_9a_2b_5c} }
10:51:47.529402 IP (tos 0x48, ttl 44, id 61290, offset 0, flags [DF], proto UDP (17), length 175)
192.158.1.38.54277 > 198.51.100.1.161: { SNMPv3 { F=apr } { USM B=10 T=39854 U="user_name" } { ScopedPDU [!scoped PDU]da_e4_d6_48_f1_ea_28_7f_bf_ce_d6_e0_ef_f7_95_06_0c_d7_79_7c_f1_4b_78_75_4f_1a_e2_00_a6_83_d5_e6_c2_82_55_0f_09_a4_7d_f1_e1_f2_a0_64_d3_c3_d7_13_c3_ae_95_8b_db} }
...
You can see that in authNoPriv
, only the authentication part is encrypted—requested OIDs are visible. In authPriv
, the entire payload is encrypted, increasing the packet size slightly. While this adds some CPU overhead, it’s negligible today given the speed of symmetric encryption with a shared key.
Configuring the Client
You can test whether SNMP is working using the built-in snmpwalk
tool.
For SNMP v2c
(community
-based):
snmpwalk -v 2c -c communityname hostname
Where:
communityname
— the community namehostname
— the agent’s hostname
For SNMP v3
with authPriv
encryption:
snmpwalk -v 3 -a SHA -A auth_pass -x AES -X priv_pass -l authPriv -u user_name hostname
Where:
SHA
— authentication algorithmauth_pass
— authentication passwordAES
— encryption algorithmpriv_pass
— encryption passwordauthPriv
— "authenticated + encrypted" security leveluser_name
— the usernamehostname
— the agent’s hostname
If that works, just fill in the corresponding values in your monitoring software.

If something isn’t working, check firewall rules on both ends. Try running snmpwalk
from the monitoring host and inspect the traffic with tcpdump
. Also test SNMP access from the agent host itself, using both the external IP and loopback addresses like 127.0.0.1
or ::1
.