diff --git a/uffd/role/models.py b/uffd/role/models.py
index 5371d65e4bb594edbacf65ffc44281bacccdd3a9..4738ce91c5f66c3f701186f9f04ea656b38598e5 100644
--- a/uffd/role/models.py
+++ b/uffd/role/models.py
@@ -24,9 +24,18 @@ class RoleUser(LdapMapping, db.Model):
 	__tablename__ = 'role-user'
 
 def update_user_groups(user):
-	user.groups.clear()
+	current_groups = set(user.groups)
+	groups = set()
 	for role in user.roles:
-		user.groups.update(role.groups)
+		groups.update(role.groups)
+	if groups == current_groups:
+		return set(), set()
+	groups_added = groups - current_groups
+	groups_removed = current_groups - groups
+	for group in groups_removed:
+		user.groups.discard(group)
+	user.groups.update(groups_added)
+	return groups_added, groups_removed
 
 User.update_groups = update_user_groups
 
diff --git a/uffd/role/views.py b/uffd/role/views.py
index e915ce5a53a5d0455aab08353ce08266480abac7..86c94145743821b547b89d87dfbd4f36299a3e0b 100644
--- a/uffd/role/views.py
+++ b/uffd/role/views.py
@@ -1,14 +1,41 @@
+import sys
+
 from flask import Blueprint, render_template, request, url_for, redirect, flash, current_app
+import click
 
 from uffd.navbar import register_navbar
 from uffd.csrf import csrf_protect
 from uffd.role.models import Role
-from uffd.user.models import Group
+from uffd.user.models import User, Group
 from uffd.session import get_current_user, login_required, is_valid_session
 from uffd.database import db
 from uffd.ldap import ldap
 
 bp = Blueprint("role", __name__, template_folder='templates', url_prefix='/role/')
+
+@bp.record
+def add_cli_commands(state):
+	@state.app.cli.command('roles-update-all', help='Update group memberships for all users based on their roles')
+	@click.option('--check-only', is_flag=True)
+	def roles_update_all(check_only): #pylint: disable=unused-variable
+		consistent = True
+		with current_app.test_request_context():
+			for user in User.query.all():
+				groups_added, groups_removed = user.update_groups()
+				if groups_added:
+					consistent = False
+					print('Adding groups [%s] to user %s'%(', '.join([group.name for group in groups_added]), user.dn))
+				if groups_removed:
+					consistent = False
+					print('Removing groups [%s] from user %s'%(', '.join([group.name for group in groups_removed]), user.dn))
+			if not check_only:
+				ldap.session.commit()
+			if check_only and not consistent:
+				print('No changes were made because --check-only is set')
+				print()
+				print('Error: LDAP groups are not consistent with roles in database')
+				sys.exit(1)
+
 @bp.before_request
 @login_required()
 def role_acl(): #pylint: disable=inconsistent-return-statements