Agent groups are how you configure anything in Wazuh 5.0. The manager configuration file no longer accepts syscheck, sca, localfile, active-response or any other capability block: those are agent-side, and the only scalable way to set them is a shared agent.conf attached to a group. Groups also gained a hard dependency in 5.0. They must exist on the manager before an agent enrols, because the agent declares its group in the enrolment handshake and the manager rejects an unknown one.

What you need

  • A Wazuh 5.0 manager and at least one agent you can restart.
  • Root on the manager, plus manager API credentials if you want to automate.
  • The SCA lesson if you arrived here looking for how to distribute a policy file.
  • The companion files: a group creation script and two sample agent.conf files.

Everything below was exercised on Linux agents. The Windows notes come from the documentation; no Windows endpoint was in the lab.

Why groups carry more weight now

In 4.x you could get away without groups. The manager held <syscheck>, <sca>, <localfile> and the rest in ossec.conf, and agents picked up a subset. That is gone. The 5.0 manager configuration file holds global, logging, remote, auth, indexer, vulnerability-detection, agent-upgrade, task-manager, wdb and cluster, and an unknown element is a startup error rather than a warning.

So every decision about what an endpoint collects now lives in one of two places: the agent’s local ossec.conf, or the shared agent.conf of a group it belongs to. Editing local files on a thousand endpoints is not a plan.

Create the groups before anything enrols

Three documented routes: the dashboard, the agent_groups tool, and the manager API.

From the manager, with root:

/var/wazuh-manager/bin/agent_groups -a -g lab-linux -q

The -q flag skips the confirmation prompt. Without it the tool asks. List what exists:

/var/wazuh-manager/bin/agent_groups -l

On the beta5 lab stack, creating a group on a fresh manager and listing gives:

$ /var/wazuh-manager/bin/agent_groups -a -g lab-linux -q
Group 'lab-linux' created.
$ /var/wazuh-manager/bin/agent_groups -l
Groups (2):
  default (0)
  lab-linux (0)
Unassigned agents: 0.

The number in brackets is the member count, and default exists on every install. After two agents enrolled, one declaring no group and one declaring lab-linux, the same command returned:

Groups (2):
  default (1)
  lab-linux (1)
Unassigned agents: 0.

“Unassigned agents: 0” stays at zero because an agent without a group is not unassigned, it is in default. Do not use that line to find misconfigured endpoints.

Through the API, which is what your build pipeline should use:

curl -k -X POST "https://<WAZUH_MANAGER_IP>:55000/groups" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"group_id": "linux-servers"}'

Get $TOKEN from POST /security/user/authenticate?raw=true with basic auth. Group names accept upper and lower case letters, numbers, dots, underscores and hyphens.

GET /groups is how a provisioning script checks before it creates. On a manager that has never had a group added, it returns only default:

{
   "data": {
      "affected_items": [
         {
            "name": "default",
            "count": 0,
            "mergedSum": "ca35f9148a3273413eccb79f149f4757",
            "configSum": "ab73af41699f13fdd81903b5f23d8d00"
         }
      ],
      "total_affected_items": 1,
      "total_failed_items": 0,
      "failed_items": []
   },
   "message": "All selected groups information was returned",
   "error": 0
}

configSum is the checksum of that group’s agent.conf and mergedSum covers the whole merged file set the group distributes. Two groups with an empty agent.conf share a configSum, as the lab’s default and lab-linux did, so use mergedSum if you want to detect that a group’s shared files changed.

From the dashboard: Agents management > Groups > Add new group.

Declare the group on the agent

The agent sends its group during enrolment, from the <enrollment> block inside <agent>:

<agent>
  <manager>
    <endpoint>192.168.1.100:1517</endpoint>
  </manager>
  <enrollment>
    <enabled>yes</enabled>
    <agent_name>web-server-01</agent_name>
    <groups>linux-servers</groups>
    <authorization_pass_path>etc/authd.pass</authorization_pass_path>
  </enrollment>
</agent>

<groups> takes a comma-separated list, and defaults to default when absent. That default is the trap: an agent deployed without the tag connects happily and lands in default, where it gets none of your configuration, and nothing in the dashboard shouts about it.

Enrolment itself is covered in the agent enrolment lesson.

Write a shared agent.conf

Each group directory on the manager holds an agent.conf, empty by default:

/var/wazuh-manager/etc/shared/
├── agent-template.conf
├── default
│   └── agent.conf
├── linux
│   └── agent.conf
├── webservers
│   └── agent.conf
└── windows
    └── agent.conf

The file is one or more <agent_config> blocks. There is no wrapping root element.

<agent_config>
  <localfile>
    <location>/var/log/syslog</location>
    <log_format>syslog</log_format>
  </localfile>
</agent_config>

Narrow a block with attributes

<agent_config> takes three attributes: name, os and profile. Each accepts a regular expression. When several are present on one block, an agent must satisfy all of them.

Attribute Matches against Typical use
name The agent name One-off exception for a single host
os The agent’s reported OS string Splitting a mixed group by platform
profile The agent’s <config-profile> value A role the agent asserts about itself

profile is the interesting one. It is set locally on the agent, under <agent> on 5.0 agents and <client> on 4.x agents, and accepts several values separated by a comma and a space. It lets the endpoint declare a role that the group does not know about, which is useful when your provisioning system knows more about the host than your Wazuh topology does.

<agent_config os="Ubuntu" profile="database">
  <syscheck>
    <frequency>1800</frequency>
  </syscheck>
</agent_config>

Validate before you activate

Write to a temporary name, validate, then rename. This is the documented practice and it exists because a broken agent.conf breaks the shared configuration for every agent in the group at once.

touch /var/wazuh-manager/etc/shared/linux-servers/agent.conf.tmp
chown wazuh-manager:wazuh-manager /var/wazuh-manager/etc/shared/linux-servers/agent.conf.tmp
chmod 660 /var/wazuh-manager/etc/shared/linux-servers/agent.conf.tmp
/var/wazuh-manager/bin/verify-agent-conf -f /var/wazuh-manager/etc/shared/linux-servers/agent.conf.tmp

Run with no arguments and the tool validates every agent.conf in the shared directory. The documented output is one Verifying [...] line per file followed by verify-agent-conf: OK.

Then rename:

mv /var/wazuh-manager/etc/shared/linux-servers/agent.conf.tmp /var/wazuh-manager/etc/shared/linux-servers/agent.conf

The manager detects the change and distributes it. No restart is required. If you want it sooner, restart the manager.

Precedence, and where the documentation disagrees

Two precedence questions come up, and they have different answers.

Shared versus local. The centralised configuration reference is unambiguous: agent.conf from the manager takes precedence over the agent’s local ossec.conf. Depending on the option, the shared setting either overrides or extends the local one. The <sca><policies> block, for instance, merges rather than replaces.

Group versus group. Here the two pages differ. The centralised configuration reference says that when an agent belongs to several groups, the configuration from the group with the lowest alphabetical order takes precedence. The group management page says the most recently assigned group wins, and that agent_groups -s lists groups in increasing priority from left to right.

Shared files behave predictably: files from every group are joined in the agent’s shared folder, and a repeated filename is overwritten by the last one added.

A group model that survives contact

One group per role and one per environment, with agents in both, is the model that has held up for me.

Group Contains Carries
linux-base Every Linux agent Baseline logs, baseline FIM scope
windows-base Every Windows agent Security and System channels, baseline FIM
web Web servers Access and error logs, web-specific SCA
db Database servers Database logs, tighter FIM
prod Production Longer FIM intervals, no command rules
pci Cardholder environment Extra policies, extra collection

Two rules keep it workable. Baseline groups own everything that every host of that platform needs, and nothing else. Overlay groups add, and never contradict. That sidesteps the precedence question entirely.

Resist a group per customer or per business unit that duplicates the baseline. That is a tenancy question, and tenancy in Wazuh is better solved with group membership plus indexer access control, which the multi-tenant lesson covers.

Move an agent between groups

Assign:

curl -k -X PUT "https://<WAZUH_MANAGER_IP>:55000/agents/012/group/webserver" \
  -H "Authorization: Bearer $TOKEN"

Or with the tool, where -f resets the agent to belong only to the new group:

/var/wazuh-manager/bin/agent_groups -a -f -i 012 -g apache

Check what an agent belongs to:

/var/wazuh-manager/bin/agent_groups -s -i 012

Documented output: The agent 'Ubuntu' with ID '012' belongs to groups: default, webserver, apache.

Remove one:

curl -k -X DELETE "https://<WAZUH_MANAGER_IP>:55000/agents/002/group/default" \
  -H "Authorization: Bearer $TOKEN"

Assignment adds rather than replaces, so an agent fixed up after landing in default keeps default unless you remove it. Whether that matters depends on what default carries, which is an argument for keeping default empty.

Group membership is written to the manager database at enrolment and persists across restarts. It is not re-sent on every connection. An agent that re-enrols under a new key, though, starts over: without <groups> in its configuration it goes to default, and there is no checksum-based guessing in 5.0 to rescue it.

Groups on the documents themselves

Group membership is not only a configuration mechanism. It travels with the data. Event, finding and state documents in the indexer all carry wazuh.agent.groups as an array alongside wazuh.agent.id and wazuh.agent.name, which means a group is available as a filter in Discover, in a dashboard, in an alerting monitor query, and in an indexer security role.

That last one is not theoretical. On the 5.0.0-beta5 lab the field is mapped as a keyword, and a document-level security rule of {"term":{"wazuh.agent.groups":"lab-linux"}} on an indexer role cut a user’s view of the events, findings and state indices down to that group’s agent alone. The mechanics are in the multi-tenant lesson.

That makes the group model a security boundary as much as a configuration one. Get it wrong and you will be re-cutting it later against live data.

What about labels?

In 4.x, <labels> let you attach arbitrary key-value metadata to an agent, and those labels appeared on every alert. As of the beta5 documentation in September 2026, there is no labels section in the Wazuh 5.0 agent configuration reference, and the page that documented it returns a 404. Nothing in the 5.0 documentation confirms a wazuh.agent.labels.* field on documents either.

Until that is settled at GA, model metadata you need for filtering as group membership, which is documented and present on the documents. If you have a 4.x design that depends on labels, put verifying their 5.0 status near the top of your migration test plan.

Common errors

ERROR: Enrollment rejected by the manager: invalid request. Invalid Group(s) Name(s)

Cause: the agent declared a group in <enrollment><groups> that does not exist on the manager. Enrolment is rejected and the agent cannot connect.

Symptom on the agent, from the beta5 lab:

$ grep ^status /var/ossec/var/run/wazuh-agentd.state
status='pending'
$ grep agentd /var/ossec/logs/ossec.log | tail -8
2026/09/23 02:41:26 wazuh-agentd:https-client: INFO: TLS verification is DISABLED (verify_mode=none).
2026/09/23 02:41:26 wazuh-agentd: ERROR: Enrollment rejected by the manager: invalid request. Invalid Group(s) Name(s)
2026/09/23 02:41:31 wazuh-agentd: INFO: Using password specified on file: etc/authd.pass
2026/09/23 02:41:31 wazuh-agentd:https-client: INFO: TLS verification is DISABLED (verify_mode=none).
2026/09/23 02:41:31 wazuh-agentd: ERROR: Enrollment rejected by the manager: invalid request. Invalid Group(s) Name(s)
...

Note the state: pending, not never_connected. The agent keeps retrying, every five seconds and then every ten, and looks alive on the endpoint while being invisible to the manager.

wazuh-manager-authd: ERROR: Invalid group: <group>

The manager side of the same failure, and the only one of the pair that names the offending group.

Fix: create the group on the manager, then restart the agent so it re-enrols. If you need the agent up immediately, remove the <groups> tag so it lands in default, then assign the group afterwards through the API.

The agent connects but gets no shared configuration

Cause: it is in default, because it enrolled without a <groups> tag. Common when an agent is deployed from an image or re-enrolled after a key reset.

Fix: check the agent’s own ossec.conf rather than the dashboard. The 4.x dashboard could show a group that existed only on the manager. Add the tag, clear client.keys, and restart so the agent enrols fresh.

The whole group stops receiving configuration after an edit

Cause: an invalid or 4.x-era agent.conf. Deprecated or renamed tags stop the shared configuration compiling.

Fix: run /var/wazuh-manager/bin/verify-agent-conf, fix what it reports, and check every block against the 5.0 agent configuration reference. This is the main reason to edit as .tmp and rename only after validation.

The dashboard shows the configuration as not synchronised

Cause: the agent has not checked in since the change, or its keepalive interval is long.

Fix: the agent’s configuration state is visible under Agents management > Summary, select the agent, then Configuration, where a synchronised agent is marked SYNCHRONIZED. notify_time on the agent controls the keepalive interval and defaults to 20 seconds; it must stay below the manager’s disconnection timeout.

repeated_offenders set in agent.conf has no effect

Cause: that option cannot be distributed through centralised configuration. It has to be in the agent’s local file, and it is not supported on Windows agents at all.

Fix: set it locally through configuration management. More on that in the active response lesson.

Official documentation for this topic: Centralized configuration for Wazuh agents. The migration guide for groups is at agent-groups-migration.md.

Next: Wazuh Notifications: Email, Slack, Telegram and Webhooks.

Files for this lesson

Every file this lesson refers to, exactly as used. Open a file to read it in the browser, or download the set as a zip. Download wazuh-agent-groups.zip. The full set for all lessons is at wazuh-tutorial-files.zip.

Frequently asked questions

Do Wazuh agent groups have to exist before an agent enrols?

Yes. In Wazuh 5.0 the agent declares its group during the enrolment handshake and the manager validates it. Verified on the 5.0.0-beta5 lab: enrolling into a group that does not exist gives the agent "Enrollment rejected by the manager: invalid request. Invalid Group(s) Name(s)", the manager logs "Invalid group" with the name, and the agent retries forever in the pending state. Create every group you intend to use before the first agent starts.

Where is agent.conf stored in Wazuh 5.0?

On the manager, at /var/wazuh-manager/etc/shared/GROUP_NAME/agent.conf. The 4.x path was /var/ossec/etc/shared/GROUP_NAME/agent.conf. Agents store everything they receive under their own etc/shared directory, regardless of which group sent it.

What happens if an agent belongs to several groups?

It receives the files from every group and the agent.conf fragments are merged. Repeated files are overwritten by the last one added. The two documentation pages describe the tie-break for conflicting settings differently, so the safe practice is to avoid conflicting settings across groups entirely.

Do I need to restart the Wazuh manager after editing agent.conf?

No. The manager detects the change and distributes it to connected agents in the group automatically. A restart only makes distribution happen sooner. Validate the file with verify-agent-conf before you make it active, because an invalid file breaks the shared configuration for the whole group.

Can an agent be removed from the default group?

Yes. Assigning a group adds it rather than replacing it, so an agent assigned a group after enrolment keeps default alongside it. Remove it with DELETE /agents/{agent_id}/group/default on the manager API, or from the Edit groups dialog in the dashboard.