diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
index bd8b6a5719..c2aa5b57e8 100644
--- a/man/systemd.resource-control.xml
+++ b/man/systemd.resource-control.xml
@@ -438,7 +438,7 @@ CPUWeight=20 DisableControllers=cpu / \
memory.max control group attribute. For details about this control group attribute, see
Memory Interface Files.
The effective configuration is reported as EffectiveMemoryMax= (the value is
- the most stringent limit of the unit and parent slices).
+ the most stringent limit of the unit and parent slices and it is capped by physical memory).
While StartupMemoryMax= applies to the startup and shutdown phases of the system,
MemoryMax= applies to normal runtime of the system, and if the former is not set also to
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index f7b776337a..60a8a55087 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -4253,6 +4253,17 @@ static uint64_t unit_get_effective_limit_one(Unit *u, CGroupLimitType type) {
assert(u);
assert(UNIT_HAS_CGROUP_CONTEXT(u));
+ if (unit_has_name(u, SPECIAL_ROOT_SLICE))
+ switch (type) {
+ case CGROUP_LIMIT_MEMORY_MAX:
+ case CGROUP_LIMIT_MEMORY_HIGH:
+ return physical_memory();
+ case CGROUP_LIMIT_TASKS_MAX:
+ return system_tasks_max();
+ default:
+ assert_not_reached();
+ }
+
cc = unit_get_cgroup_context(u);
switch (type) {
/* Note: on legacy/hybrid hierarchies memory_max stays CGROUP_LIMIT_MAX unless configured