diff --git a/src/components/Status/index.vue b/src/components/Status/index.vue
index f2b071c2bc8c169aa032e189cdef12c18d873d9f..a3283a29e03347fe7265f9164f9d02c5ce708ad4 100644
--- a/src/components/Status/index.vue
+++ b/src/components/Status/index.vue
@@ -23,7 +23,7 @@
             </router-link>
           </div>
         </div>
-        <div class="status-actions">
+        <div v-if="isPrivileged(['messages_delete'], [])" class="status-actions">
           <div class="status-tags">
             <el-tag v-if="status.sensitive" type="warning" size="large">{{ $t('reports.sensitive') }}</el-tag>
             <el-tag size="large">{{ capitalizeFirstLetter(status.visibility) }}</el-tag>
@@ -184,6 +184,11 @@ export default {
     capitalizeFirstLetter(str) {
       return str.charAt(0).toUpperCase() + str.slice(1)
     },
+    isPrivileged(accepted_privileges, accepted_roles) {
+      const user_privileges = this.$store.getters.privileges
+      const user_roles = this.$store.getters.roles
+      return accepted_privileges.some(privilege => user_privileges.indexOf(privilege) >= 0) || accepted_roles.some(role => user_roles.indexOf(role) >= 0)
+    },
     changeStatus(statusId, isSensitive, visibility) {
       this.$store.dispatch('ChangeStatusScope', {
         statusId,
diff --git a/src/permission.js b/src/permission.js
index 8e155e5b18c9129e5a74e98841059bde8767b9fc..0530bdcf1af4182e5a450903b6f8fbd9c468df63 100644
--- a/src/permission.js
+++ b/src/permission.js
@@ -14,6 +14,25 @@ function hasPermission(roles, permissionRoles) {
   return roles.some(role => permissionRoles.indexOf(role) >= 0)
 }
 
+function isPrivileged(route, privileges) {
+  if (!route.required_privileges) {
+    return true
+  }
+
+  // We check for all the required privileges if the user has it
+  // If there's at least one privilege missing, the user isn't privileged so we return false
+  // If the logged in user has all required privileges, we return true
+  return route.required_privileges.map(required_privilege => privileges.indexOf(required_privilege)).indexOf(-1) === -1
+}
+
+function findFirstUnhiddenPath(addRouters) {
+  const unhiddenRoute = addRouters.find((route) => !route.hidden)
+  if (unhiddenRoute) {
+    return unhiddenRoute.path + '/index'
+  }
+  return '/401'
+}
+
 const whiteList = ['/login', '/auth-redirect', '/login-pleroma']// no redirect whitelist
 
 export const beforeEachRoute = (to, from, next) => {
@@ -24,11 +43,20 @@ export const beforeEachRoute = (to, from, next) => {
       next({ path: '/' })
       NProgress.done() // if current page is dashboard will not trigger	afterEach hook, so manually handle it
     } else {
-      if (store.getters.roles.length === 0) {
+      if (store.getters.roles.length === 0 && store.getters.privileges.length === 0) {
         store.dispatch('GetUserInfo').then(res => {
-          const roles = res.data.pleroma.is_admin ? ['admin'] : []
+          const roles = store.getters.roles
+          const privileges = store.getters.privileges
+
           store.dispatch('GenerateRoutes', { roles }).then(() => {
-            store.getters.addRouters.forEach(route => router.addRoute(route))
+            const addRouters = store.getters.addRouters
+            addRouters.forEach(route => {
+              route.hidden = route.hidden || !isPrivileged(route, privileges)
+              if (route.path === '') {
+                route.redirect = findFirstUnhiddenPath(addRouters)
+              }
+              router.addRoute(route)
+            })
             next({ ...to, replace: true })
           })
         }).catch((err) => {
diff --git a/src/router/index.js b/src/router/index.js
index 4d0463182d2f404faf7ae26b2b14b2685c3e0af4..a44a2aa98b2d86d3ccbe081e3f6a5fa6392f33a3 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -36,6 +36,7 @@ const settingsChildren = () => {
 const settings = {
   path: '/settings',
   component: Layout,
+  roles: ['admin'],
   name: 'Settings',
   hasSubmenu: true,
   meta: { title: 'settings', icon: 'el-icon-setting', noCache: true },
@@ -45,6 +46,7 @@ const statusesDisabled = disabledFeatures.includes('statuses')
 const statuses = {
   path: '/statuses',
   component: Layout,
+  required_privileges: ['messages_read', 'messages_delete'],
   children: [
     {
       path: 'index',
@@ -59,6 +61,7 @@ const reportsDisabled = disabledFeatures.includes('reports')
 const reports = {
   path: '/reports',
   component: Layout,
+  required_privileges: ['reports_manage_reports'],
   children: [
     {
       path: 'index',
@@ -73,6 +76,7 @@ const invitesDisabled = disabledFeatures.includes('invites')
 const invites = {
   path: '/invites',
   component: Layout,
+  required_privileges: ['users_manage_invites'],
   children: [
     {
       path: 'index',
@@ -87,6 +91,7 @@ const relaysDisabled = disabledFeatures.includes('relays')
 const relays = {
   path: '/relays',
   component: Layout,
+  roles: ['admin'],
   children: [
     {
       path: 'index',
@@ -101,6 +106,7 @@ const moderationLogDisabled = disabledFeatures.includes('moderation-log')
 const moderationLog = {
   path: '/moderation_log',
   component: Layout,
+  required_privileges: ['moderation_log_read'],
   children: [
     {
       path: 'index',
@@ -115,6 +121,7 @@ const mediaProxyCacheDisabled = disabledFeatures.includes('media-proxy-cache')
 const mediaProxyCache = {
   path: '/media_proxy_cache',
   component: Layout,
+  roles: ['admin'],
   children: [
     {
       path: 'index',
@@ -161,12 +168,6 @@ export const constantRouterMap = [
     path: '/401',
     component: () => import('@/views/errorPage/401'),
     hidden: true
-  },
-  {
-    path: '',
-    component: Layout,
-    redirect: '/users/index',
-    hidden: true
   }
 ]
 
@@ -180,6 +181,7 @@ export const asyncRouterMap = [
   {
     path: '/users',
     component: Layout,
+    required_privileges: ['users_read'],
     children: [
       {
         path: 'index',
@@ -191,11 +193,11 @@ export const asyncRouterMap = [
   },
   ...(statusesDisabled ? [] : [statuses]),
   ...(reportsDisabled ? [] : [reports]),
-  ...(invitesDisabled ? [] : [invites]),
   ...(moderationLogDisabled ? [] : [moderationLog]),
   ...(relaysDisabled ? [] : [relays]),
   ...(mediaProxyCacheDisabled ? [] : [mediaProxyCache]),
   ...(settingsDisabled ? [] : [settings]),
+  ...(invitesDisabled ? [] : [invites]),
   {
     path: '/users/:id',
     component: Layout,
@@ -244,5 +246,10 @@ export const asyncRouterMap = [
     ],
     hidden: true
   },
-  { path: '*', redirect: '/404', hidden: true }
+  { path: '*', redirect: '/404', hidden: true },
+  {
+    path: '',
+    component: Layout,
+    hidden: true
+  }
 ]
diff --git a/src/store/getters.js b/src/store/getters.js
index a287712ddb89645304ad06dab251cd12ced6aaa9..83621ac6b48b48882e1fbc3751125360cfc1a5ab 100644
--- a/src/store/getters.js
+++ b/src/store/getters.js
@@ -11,6 +11,7 @@ const getters = {
   introduction: state => state.user.introduction,
   status: state => state.user.status,
   roles: state => state.user.roles,
+  privileges: state => state.user.privileges,
   setting: state => state.user.setting,
   permission_routers: state => state.permission.routers,
   addRouters: state => state.permission.addRouters,
diff --git a/src/store/modules/app.js b/src/store/modules/app.js
index e06953aaaac6fc423e1f9e6ab094deb87c6ab986..b585da5bf3f6fc9578e20f29139b77804fa0e324 100644
--- a/src/store/modules/app.js
+++ b/src/store/modules/app.js
@@ -51,6 +51,9 @@ const app = {
       commit('CLOSE_SIDEBAR', withoutAnimation)
     },
     async NeedReboot({ commit, getters }) {
+      if (!getters.roles.includes('admin')) {
+        return
+      }
       const response = await needReboot(getters.authHost, getters.token)
       commit('TOGGLE_REBOOT', response.data['need_reboot'])
     },
diff --git a/src/store/modules/user.js b/src/store/modules/user.js
index 7b98ed58d0309ccdd4aa6f2337683a31e930800f..0616011aa7df3c40c1e80a74ed757f085d86e44d 100644
--- a/src/store/modules/user.js
+++ b/src/store/modules/user.js
@@ -14,6 +14,7 @@ const user = {
     avatar: '',
     introduction: '',
     roles: [],
+    privileges: [],
     setting: {
       articlePlatform: []
     },
@@ -45,6 +46,9 @@ const user = {
     SET_ROLES: (state, roles) => {
       state.roles = roles
     },
+    SET_PRIVILEGES: (state, privileges) => {
+      state.privileges = privileges || []
+    },
     SET_ID: (state, id) => {
       state.id = id
     },
@@ -82,16 +86,21 @@ const user = {
       return new Promise((resolve, reject) => {
         getUserInfo(state.token, state.authHost).then(response => {
           const data = response.data
-          const message = '<span>This user doesn\`t have admin rights. Try another credentials or see the </span>' +
+          const is_admin = data.pleroma?.is_admin
+          const is_privileged = !!data.pleroma?.privileges?.length
+          const message = '<span>This user doesn\'t have admin/moderator rights or privileges. Try another account or see the </span>' +
             '<u><a target="_blank" href="https://docs.pleroma.social/backend/administration/CLI_tasks/user/#set-the-value-of-the-given-users-settings">docs</a></u>' +
-            '<span> to find out how to make this user an admin</span>'
+            '<span> to find out how to grant permissions to this user</span>'
 
           if (!data) {
             reject('Verification failed, please login again.')
           }
 
-          if (data.pleroma && data.pleroma.is_admin) {
-            commit('SET_ROLES', ['admin'])
+          if (is_admin || is_privileged) {
+            if (is_admin) {
+              commit('SET_ROLES', ['admin'])
+            }
+            commit('SET_PRIVILEGES', data.pleroma.privileges || [])
           } else {
             reject(message)
           }
diff --git a/src/store/modules/userProfile.js b/src/store/modules/userProfile.js
index 40af065c53c656ff1008dfe9d692d3d637064e2e..000e07a6242292dac60ad093b366a102a4c64849 100644
--- a/src/store/modules/userProfile.js
+++ b/src/store/modules/userProfile.js
@@ -41,8 +41,12 @@ const userProfile = {
       commit('SET_USER', userResponse.data)
       commit('SET_USER_PROFILE_LOADING', false)
 
-      dispatch('FetchUserStatuses', { userId, godmode })
-      dispatch('FetchUserChats', { userId })
+      if (getters.roles.includes('admin') || getters.privileges.includes('messages_read')) {
+        dispatch('FetchUserStatuses', { userId, godmode })
+        if (!godmode) {
+          dispatch('FetchUserChats', { userId })
+        }
+      }
     },
     FetchUserStatuses({ commit, dispatch, getters }, { userId, godmode }) {
       commit('SET_STATUSES_LOADING', true)
@@ -61,8 +65,10 @@ const userProfile = {
       commit('SET_CHATS_LOADING', false)
     },
     async FetchUserCredentials({ commit, getters }, { nickname }) {
-      const userResponse = await fetchUserCredentials(nickname, getters.authHost, getters.token)
-      commit('SET_USER_CREDENTIALS', userResponse.data)
+      if (getters.roles.includes('admin') || getters.privileges.includes('users_manage_credentials')) {
+        const userResponse = await fetchUserCredentials(nickname, getters.authHost, getters.token)
+        commit('SET_USER_CREDENTIALS', userResponse.data)
+      }
     },
     SetStatuses({ commit }, statuses) {
       commit('SET_STATUSES', statuses)
diff --git a/src/store/modules/users.js b/src/store/modules/users.js
index 0ba8c998b31f7aceeacebc3a1c24044625a29094..7648bd0c109bc440124d886458b120398be5d3cc 100644
--- a/src/store/modules/users.js
+++ b/src/store/modules/users.js
@@ -220,6 +220,10 @@ const users = {
       dispatch('FetchTagPolicySetting')
     },
     async FetchTagPolicySetting({ commit, getters }) {
+      if (!getters.roles.includes('admin')) {
+        return
+      }
+      // XXX: Use nodeinfo?
       const { data } = await fetchSettings(getters.authHost, getters.token)
       const mrfSettings = data.configs.find(el => el.key === ':mrf')
         ? data.configs.find(el => el.key === ':mrf').value
diff --git a/src/views/layout/components/Sidebar/index.vue b/src/views/layout/components/Sidebar/index.vue
index ed8bd849640e0898a12d0e2ab2b682a128a87ab7..d22f95c4e83824677b33efdbf916130694741c8a 100644
--- a/src/views/layout/components/Sidebar/index.vue
+++ b/src/views/layout/components/Sidebar/index.vue
@@ -27,6 +27,7 @@ export default {
     ...mapGetters([
       'permission_routers',
       'roles',
+      'privileges',
       'sidebar',
       'tabs'
     ]),
@@ -38,7 +39,9 @@ export default {
     }
   },
   mounted() {
-    this.$store.dispatch('FetchOpenReportsCount')
+    if (this.privileges?.indexOf('reports_manage_reports') !== -1) {
+      this.$store.dispatch('FetchOpenReportsCount')
+    }
   },
   methods: {
     getMergedRoutes() {
diff --git a/src/views/users/components/ModerationDropdown.vue b/src/views/users/components/ModerationDropdown.vue
index 57023192af255e3756cc729d129c2e6be6af4a1b..913e52458ec1ede7a91ce0c70df74ca3be914a04 100644
--- a/src/views/users/components/ModerationDropdown.vue
+++ b/src/views/users/components/ModerationDropdown.vue
@@ -1,5 +1,5 @@
 <template>
-  <el-dropdown :hide-on-click="false" size="small" trigger="click" placement="top-start" @click.native.stop>
+  <el-dropdown v-if="isPrivileged(['users_manage_activation_state', 'users_delete', 'users_manage_tags', 'users_manage_credentials'], ['admin'])" :hide-on-click="false" size="small" trigger="click" placement="top-start" @click.native.stop>
     <div>
       <el-button v-if="page === 'users'" type="text" class="el-dropdown-link">
         {{ $t('users.moderation') }}
@@ -17,6 +17,7 @@
     </div>
     <el-dropdown-menu slot="dropdown" class="moderation-dropdown-menu">
       <el-dropdown-item
+        v-if="isPrivileged([], ['admin'])"
         class="actor-type-dropdown">
         <el-select v-model="actorType" :placeholder="$t('userProfile.actorType')" class="actor-type-select">
           <el-option :label="$t('users.service')" value="Service"/>
@@ -24,51 +25,51 @@
         </el-select>
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="showAdminAction(user)"
+        v-if="isPrivileged([], ['admin']) && showAdminAction(user)"
         divided
         @click.native="toggleUserRight(user, 'admin')">
         {{ user.roles.admin ? $t('users.revokeAdmin') : $t('users.grantAdmin') }}
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="showAdminAction(user)"
+        v-if="isPrivileged([], ['admin']) && showAdminAction(user)"
         @click.native="toggleUserRight(user, 'moderator')">
         {{ user.roles.moderator ? $t('users.revokeModerator') : $t('users.grantModerator') }}
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="showDeactivatedButton(user.id) && page !== 'statusPage'"
+        v-if="isPrivileged(['users_manage_activation_state'], []) && showDeactivatedButton(user.id) && page !== 'statusPage'"
         :divided="showAdminAction(user)"
         @click.native="toggleActivation(user)">
         {{ !user.is_active ? $t('users.activateAccount') : $t('users.deactivateAccount') }}
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="showDeactivatedButton(user.id) && page !== 'statusPage'"
+        v-if="isPrivileged(['users_delete'], []) && showDeactivatedButton(user.id) && page !== 'statusPage'"
         @click.native="handleDeletion(user)">
         {{ $t('users.deleteAccount') }}
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="user.local && !user.is_approved"
+        v-if="isPrivileged([], ['admin']) && user.local && !user.is_approved"
         divided
         @click.native="handleAccountApproval(user)">
         {{ $t('users.approveAccount') }}
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="user.local && !user.is_approved"
+        v-if="isPrivileged([], ['admin']) && user.local && !user.is_approved"
         @click.native="handleAccountRejection(user)">
         {{ $t('users.rejectAccount') }}
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="user.local && !user.is_confirmed"
+        v-if="isPrivileged([], ['admin']) && user.local && !user.is_confirmed"
         divided
         @click.native="handleEmailConfirmation(user)">
         {{ $t('users.confirmAccount') }}
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="user.local && !user.is_confirmed"
+        v-if="isPrivileged([], ['admin']) && user.local && !user.is_confirmed"
         @click.native="handleConfirmationResend(user)">
         {{ $t('users.resendConfirmation') }}
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="tagPolicyEnabled"
+        v-if="isPrivileged(['users_manage_tags'], []) && tagPolicyEnabled"
         :divided="showAdminAction(user)"
         :class="{ 'active-tag': user.tags.includes('mrf_tag:media-force-nsfw') }"
         @click.native="toggleTag(user, 'mrf_tag:media-force-nsfw')">
@@ -76,60 +77,60 @@
         <i v-if="user.tags.includes('mrf_tag:media-force-nsfw')" class="el-icon-check"/>
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="tagPolicyEnabled"
+        v-if="isPrivileged(['users_manage_tags'], []) && tagPolicyEnabled"
         :class="{ 'active-tag': user.tags.includes('mrf_tag:media-strip') }"
         @click.native="toggleTag(user, 'mrf_tag:media-strip')">
         {{ $t('users.stripMedia') }}
         <i v-if="user.tags.includes('mrf_tag:media-strip')" class="el-icon-check"/>
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="tagPolicyEnabled"
+        v-if="isPrivileged(['users_manage_tags'], []) && tagPolicyEnabled"
         :class="{ 'active-tag': user.tags.includes('mrf_tag:force-unlisted') }"
         @click.native="toggleTag(user, 'mrf_tag:force-unlisted')">
         {{ $t('users.forceUnlisted') }}
         <i v-if="user.tags.includes('mrf_tag:force-unlisted')" class="el-icon-check"/>
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="tagPolicyEnabled"
+        v-if="isPrivileged(['users_manage_tags'], []) && tagPolicyEnabled"
         :class="{ 'active-tag': user.tags.includes('mrf_tag:sandbox') }"
         @click.native="toggleTag(user, 'mrf_tag:sandbox')">
         {{ $t('users.sandbox') }}
         <i v-if="user.tags.includes('mrf_tag:sandbox')" class="el-icon-check"/>
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="user.local && tagPolicyEnabled"
+        v-if="isPrivileged(['users_manage_tags'], []) && user.local && tagPolicyEnabled"
         :class="{ 'active-tag': user.tags.includes('mrf_tag:disable-remote-subscription') }"
         @click.native="toggleTag(user, 'mrf_tag:disable-remote-subscription')">
         {{ $t('users.disableRemoteSubscription') }}
         <i v-if="user.tags.includes('mrf_tag:disable-remote-subscription')" class="el-icon-check"/>
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="user.local && tagPolicyEnabled"
+        v-if="isPrivileged(['users_manage_tags'], []) && user.local && tagPolicyEnabled"
         :class="{ 'active-tag': user.tags.includes('mrf_tag:disable-any-subscription') }"
         @click.native="toggleTag(user, 'mrf_tag:disable-any-subscription')">
         {{ $t('users.disableAnySubscription') }}
         <i v-if="user.tags.includes('mrf_tag:disable-any-subscription')" class="el-icon-check"/>
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="!tagPolicyEnabled"
+        v-if="isPrivileged(['users_manage_tags'], []) && isPrivileged([], ['admin']) && !tagPolicyEnabled"
         divided
         class="no-hover"
         @click.native="enableTagPolicy">
         {{ $t('users.enableTagPolicy') }}
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="user.local"
+        v-if="isPrivileged(['users_manage_credentials'], []) && user.local"
         divided
         @click.native="getPasswordResetToken(user.nickname)">
         {{ $t('users.getPasswordResetToken') }}
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="user.local"
+        v-if="isPrivileged([], ['admin']) && user.local"
         @click.native="requirePasswordReset(user)">
         {{ $t('users.requirePasswordReset') }}
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="user.local"
+        v-if="isPrivileged([], ['admin']) && user.local"
         @click.native="disableMfa(user.nickname)">
         {{ $t('users.disableMfa') }}
       </el-dropdown-item>
@@ -181,6 +182,11 @@ export default {
     disableMfa(nickname) {
       this.$store.dispatch('DisableMfa', nickname)
     },
+    isPrivileged(accepted_privileges, accepted_roles) {
+      const user_privileges = this.$store.getters.privileges
+      const user_roles = this.$store.getters.roles
+      return accepted_privileges.some(privilege => user_privileges.indexOf(privilege) >= 0) || accepted_roles.some(role => user_roles.indexOf(role) >= 0)
+    },
     enableTagPolicy() {
       this.$confirm(
         this.$t('users.confirmEnablingTagPolicy'),
diff --git a/src/views/users/components/MultipleUsersMenu.vue b/src/views/users/components/MultipleUsersMenu.vue
index 7ebd4ef6652aa75ce14cbd6f5ecc6942b6cffc3e..a98ba0217c80f8a81f788c02f20addf6f28fdcce 100644
--- a/src/views/users/components/MultipleUsersMenu.vue
+++ b/src/views/users/components/MultipleUsersMenu.vue
@@ -1,5 +1,5 @@
 <template>
-  <el-dropdown size="small" trigger="click" placement="bottom-start">
+  <el-dropdown v-if="isPrivileged(['users_manage_invites', 'users_delete', 'users_manage_activation_state', 'users_manage_tags'], ['admin'])" size="small" trigger="click" placement="bottom-start" class="multiple-users-menu" >
     <el-button v-if="isDesktop" class="actions-button">
       <span class="actions-button-container">
         <span>
@@ -11,57 +11,70 @@
     </el-button>
     <el-dropdown-menu v-if="showDropdownForMultipleUsers" slot="dropdown">
       <el-dropdown-item
+        v-if="isPrivileged([], ['admin'])"
+        class="grant-right-to-multiple-users"
         @click.native="grantRightToMultipleUsers('admin')">
         {{ $t('users.grantAdmin') }}
       </el-dropdown-item>
       <el-dropdown-item
+        v-if="isPrivileged([], ['admin'])"
         @click.native="revokeRightFromMultipleUsers('admin')">
         {{ $t('users.revokeAdmin') }}
       </el-dropdown-item>
       <el-dropdown-item
+        v-if="isPrivileged([], ['admin'])"
         @click.native="grantRightToMultipleUsers('moderator')">
         {{ $t('users.grantModerator') }}
       </el-dropdown-item>
       <el-dropdown-item
+        v-if="isPrivileged([], ['admin'])"
         @click.native="revokeRightFromMultipleUsers('moderator')">
         {{ $t('users.revokeModerator') }}
       </el-dropdown-item>
       <el-dropdown-item
+        v-if="isPrivileged(['users_manage_invites'], [])"
         divided
         @click.native="approveAccountsForMultipleUsers">
         {{ $t('users.approveAccounts') }}
       </el-dropdown-item>
       <el-dropdown-item
+        v-if="isPrivileged(['users_delete'], [])"
         @click.native="rejectAccountsForMultipleUsers">
         {{ $t('users.rejectAccounts') }}
       </el-dropdown-item>
       <el-dropdown-item
+        v-if="isPrivileged([], ['admin'])"
         divided
         @click.native="confirmAccountsForMultipleUsers">
         {{ $t('users.confirmAccounts') }}
       </el-dropdown-item>
       <el-dropdown-item
+        v-if="isPrivileged([], ['admin'])"
         @click.native="resendConfirmationForMultipleUsers">
         {{ $t('users.resendConfirmation') }}
       </el-dropdown-item>
       <el-dropdown-item
+        v-if="isPrivileged(['users_manage_activation_state'], [])"
         divided
         @click.native="activateMultipleUsers">
         {{ $t('users.activateAccounts') }}
       </el-dropdown-item>
       <el-dropdown-item
+        v-if="isPrivileged(['users_manage_activation_state'], [])"
         @click.native="deactivateMultipleUsers">
         {{ $t('users.deactivateAccounts') }}
       </el-dropdown-item>
       <el-dropdown-item
+        v-if="isPrivileged(['users_delete'], [])"
         @click.native="deleteMultipleUsers">
         {{ $t('users.deleteAccounts') }}
       </el-dropdown-item>
       <el-dropdown-item
+        v-if="isPrivileged([], ['admin'])"
         @click.native="requirePasswordReset">
         {{ $t('users.requirePasswordReset') }}
       </el-dropdown-item>
-      <el-dropdown-item v-if="tagPolicyEnabled" divided class="no-hover">
+      <el-dropdown-item v-if="tagPolicyEnabled && isPrivileged(['users_manage_tags'], [])" divided class="no-hover">
         <div class="tag-container">
           <span class="tag-text">{{ $t('users.forceNsfw') }}</span>
           <el-button-group class="tag-button-group">
@@ -74,7 +87,7 @@
           </el-button-group>
         </div>
       </el-dropdown-item>
-      <el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
+      <el-dropdown-item v-if="tagPolicyEnabled && isPrivileged(['users_manage_tags'], [])" class="no-hover">
         <div class="tag-container">
           <span class="tag-text">{{ $t('users.stripMedia') }}</span>
           <el-button-group class="tag-button-group">
@@ -87,7 +100,7 @@
           </el-button-group>
         </div>
       </el-dropdown-item>
-      <el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
+      <el-dropdown-item v-if="tagPolicyEnabled && isPrivileged(['users_manage_tags'], [])" class="no-hover">
         <div class="tag-container">
           <span class="tag-text">{{ $t('users.forceUnlisted') }}</span>
           <el-button-group class="tag-button-group">
@@ -100,7 +113,7 @@
           </el-button-group>
         </div>
       </el-dropdown-item>
-      <el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
+      <el-dropdown-item v-if="tagPolicyEnabled && isPrivileged(['users_manage_tags'], [])" class="no-hover">
         <div class="tag-container">
           <span class="tag-text">{{ $t('users.sandbox') }}</span>
           <el-button-group class="tag-button-group">
@@ -113,7 +126,7 @@
           </el-button-group>
         </div>
       </el-dropdown-item>
-      <el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
+      <el-dropdown-item v-if="tagPolicyEnabled && isPrivileged(['users_manage_tags'], [])" class="no-hover">
         <div class="tag-container">
           <span class="tag-text">{{ $t('users.disableRemoteSubscriptionForMultiple') }}</span>
           <el-button-group class="tag-button-group">
@@ -126,7 +139,7 @@
           </el-button-group>
         </div>
       </el-dropdown-item>
-      <el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
+      <el-dropdown-item v-if="tagPolicyEnabled && isPrivileged(['users_manage_tags'], [])" class="no-hover">
         <div class="tag-container">
           <span class="tag-text">{{ $t('users.disableAnySubscriptionForMultiple') }}</span>
           <el-button-group class="tag-button-group">
@@ -140,14 +153,14 @@
         </div>
       </el-dropdown-item>
       <el-dropdown-item
-        v-if="!tagPolicyEnabled"
+        v-if="!tagPolicyEnabled && isPrivileged([], ['admin']) && isPrivileged(['users_manage_tags'], [])"
         divided
         @click.native="enableTagPolicy">
         {{ $t('users.enableTagPolicy') }}
       </el-dropdown-item>
     </el-dropdown-menu>
     <el-dropdown-menu v-else slot="dropdown">
-      <el-dropdown-item>
+      <el-dropdown-item class="select-users">
         {{ $t('users.selectUsers') }}
       </el-dropdown-item>
     </el-dropdown-menu>
@@ -257,6 +270,11 @@ export default {
         }
       }
     },
+    isPrivileged(accepted_privileges, accepted_roles) {
+      const user_privileges = this.$store.getters.privileges
+      const user_roles = this.$store.getters.roles
+      return accepted_privileges.some(privilege => user_privileges.indexOf(privilege) >= 0) || accepted_roles.some(role => user_roles.indexOf(role) >= 0)
+    },
     enableTagPolicy() {
       this.$confirm(
         this.$t('users.confirmEnablingTagPolicy'),
diff --git a/src/views/users/index.vue b/src/views/users/index.vue
index 510c7b23efbdebbbf0f109acf9160dedbbf0fa9a..e3f0bfc2933ac970887b5fcf141e8d35e083d333 100644
--- a/src/views/users/index.vue
+++ b/src/views/users/index.vue
@@ -17,7 +17,7 @@
         @input="handleDebounceSearchInput"/>
     </div>
     <div class="actions-container">
-      <el-button class="actions-button" @click="createAccountDialogOpen = true">
+      <el-button v-if="isPrivileged([], ['admin'])" class="actions-button" @click="createAccountDialogOpen = true">
         <span class="create-account">
           <i class="el-icon-plus"/>
           {{ $t('users.createAccount') }}
@@ -208,6 +208,11 @@ export default {
     clearSelection() {
       this.$refs.usersTable.clearSelection()
     },
+    isPrivileged(accepted_privileges, accepted_roles) {
+      const user_privileges = this.$store.getters.privileges
+      const user_roles = this.$store.getters.roles
+      return accepted_privileges.some(privilege => user_privileges.indexOf(privilege) >= 0) || accepted_roles.some(role => user_roles.indexOf(role) >= 0)
+    },
     closeResetPasswordDialog() {
       this.resetPasswordDialogOpen = false
       this.$store.dispatch('RemovePasswordToken')
diff --git a/test/components/Status/index.test.js b/test/components/Status/index.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..2401eec6c4e7b2b1dec8aed1040ae23276c24f11
--- /dev/null
+++ b/test/components/Status/index.test.js
@@ -0,0 +1,71 @@
+import Vuex from 'vuex'
+import { mount, createLocalVue, config } from '@vue/test-utils'
+import flushPromises from 'flush-promises'
+import Element from 'element-ui'
+import Statuses from '@/views/statuses/index'
+import {
+  storeNoPrivilegesNoRoles,
+  storeWithPrivilegesMessagesDeleteNoRoles
+} from './store.conf'
+import { cloneDeep } from 'lodash'
+
+config.mocks["$t"] = (t) => t
+config.stubs.transition = false
+
+const localVue = createLocalVue()
+localVue.use(Vuex)
+localVue.use(Element)
+
+jest.mock('@/api/app')
+jest.mock('@/api/nodeInfo')
+jest.mock('@/api/peers')
+jest.mock('@/api/settings')
+jest.mock('@/api/status')
+
+describe('Statuses', () => {
+  it('Allows to change scope when privileged', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeWithPrivilegesMessagesDeleteNoRoles))
+    const wrapper = mount(Statuses, {
+      store: store,
+      localVue
+    })
+    await flushPromises()
+
+    store.dispatch('HandleFilterChange', 'heaven.com')
+    wrapper.vm.handleFilterChange()
+    await flushPromises()
+
+    const menu = wrapper.find('.status-actions')
+    const menu_items = menu.findAll('.el-dropdown-menu__item')
+    const menu_items_text = menu_items.wrappers.map(menu_item => menu_item.text()).sort()
+
+    expect(menu.isVisible()).toEqual(true)
+    expect(menu_items_text).toEqual([
+      'reports.addSensitive',
+      'reports.deleteStatus',
+      'reports.private',
+      'reports.public'
+    ])
+
+    done()
+  })
+
+  it('Allows to change scope when not privileged', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeNoPrivilegesNoRoles))
+    const wrapper = mount(Statuses, {
+      store: store,
+      localVue
+    })
+    await flushPromises()
+
+    store.dispatch('HandleFilterChange', 'heaven.com')
+    wrapper.vm.handleFilterChange()
+    await flushPromises()
+
+    const menu = wrapper.find('.status-actions')
+
+    expect(menu.exists()).toEqual(false)
+
+    done()
+  })
+})
diff --git a/test/components/Status/store.conf.js b/test/components/Status/store.conf.js
new file mode 100644
index 0000000000000000000000000000000000000000..18945a7457d7839754c94ba94634f112cb5e4b33
--- /dev/null
+++ b/test/components/Status/store.conf.js
@@ -0,0 +1,47 @@
+import app from '@/store/modules/app'
+import peers from '@/store/modules/peers'
+import user from '@/store/modules/user'
+import users from '@/store/modules/users'
+import settings from '@/store/modules/settings'
+import status from '@/store/modules/status'
+import getters from '@/store/getters'
+
+export const storeNoPrivilegesNoRoles = {
+  modules: {
+    app,
+    peers,
+    settings,
+    status,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        authHost: 'localhost:4000',
+        roles: [],
+        privileges: []
+      }
+    },
+    users
+  },
+  getters
+}
+
+export const storeWithPrivilegesMessagesDeleteNoRoles = {
+  modules: {
+    app,
+    peers,
+    settings,
+    status,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        authHost: 'localhost:4000',
+        roles: [],
+        privileges: ['messages_delete']
+      }
+    },
+    users
+  },
+  getters
+}
diff --git a/test/views/statuses/statusShowStore.conf.js b/test/views/statuses/statusShowStore.conf.js
index c83a8660947fb0ba52e56c5b44eb54cc7e89d4a1..38a3ec18c77969759f0f8cd8e0f4ebc40a00080b 100644
--- a/test/views/statuses/statusShowStore.conf.js
+++ b/test/views/statuses/statusShowStore.conf.js
@@ -13,7 +13,20 @@ export default {
     peers,
     settings,
     status,
-    user,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: ['admin'],
+        privileges: [
+          'users_manage_activation_state',
+          'users_delete',
+          'users_manage_tags',
+          'users_manage_credentials',
+          'messages_delete'
+        ]
+      }
+    },
     userProfile,
     users
   },
diff --git a/test/views/users/components/ModerationDropdown.test.js b/test/views/users/components/ModerationDropdown.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..7d6013dd804f5fd9dea8b088d3cfcbdebf3e5696
--- /dev/null
+++ b/test/views/users/components/ModerationDropdown.test.js
@@ -0,0 +1,210 @@
+import Vuex from 'vuex'
+import { mount, createLocalVue, config, RouterLinkStub } from '@vue/test-utils'
+import flushPromises from 'flush-promises'
+import Element from 'element-ui'
+import Users from '@/views/users/index'
+import {
+  storeNoPrivilegesNoRoles,
+  storeWithTagPolicyNoPrivilegesRolesAdmin,
+  storeWithPrivilegesUsersManageActivationStateNoRoles,
+  storeWithPrivilegesUsersDeleteNoRoles,
+  storeWithTagPolicyPrivilegesUsersManageTagsNoRoles,
+  storeWithTagPolicyPrivilegesUsersManageTagsRolesAdmin,
+  storeWithPrivilegesUsersManageCredentialsNoRoles
+} from './store.conf'
+import { cloneDeep } from 'lodash'
+
+config.mocks["$t"] = (key) => key
+
+const localVue = createLocalVue()
+localVue.use(Vuex)
+localVue.use(Element)
+
+jest.mock('@/api/app')
+jest.mock('@/api/nodeInfo')
+jest.mock('@/api/users')
+jest.mock('@/api/settings')
+
+describe('The Multiple Users Moderation Menu', () => {
+  it('doesnt show for someone with no privileges and no roles', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeNoPrivilegesNoRoles))
+    const wrapper = mount(Users, {
+      store,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    await flushPromises()
+
+    expect(wrapper.find('.moderation-dropdown-menu').exists()).toEqual(false)
+    done()
+  })
+
+  it('shows for someone with admin role and shows proper entries', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeWithTagPolicyNoPrivilegesRolesAdmin))
+    const wrapper = mount(Users, {
+      store,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    await flushPromises()
+    const menu = wrapper.findAll('.moderation-dropdown-menu').at(0)
+    const menu_items = menu.findAll('.el-dropdown-menu__item')
+    const menu_items_text = menu_items.wrappers.map(menu_item => menu_item.text()).sort()
+
+    expect(menu.isVisible()).toEqual(true)
+    expect(menu_items_text).toEqual([
+      'users.disableMfa',
+      'users.grantModerator',
+      'users.requirePasswordReset',
+      'users.revokeAdmin',
+      'users.service users.person',
+    ])
+
+    store.state.users.mrfPolicies = []
+    await flushPromises()
+
+    expect(menu_items.length).toEqual(menu_items_text.length)
+    done()
+  })
+
+  it('shows for someone with users_manage_activation_state privilege and shows proper entries', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeWithPrivilegesUsersManageActivationStateNoRoles))
+    const wrapper = mount(Users, {
+      store,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    await flushPromises()
+    const menu = wrapper.findAll('.moderation-dropdown-menu').at(0)
+    const menu_items = menu.findAll('.el-dropdown-menu__item')
+    const menu_items_text = menu_items.wrappers.map(menu_item => menu_item.text()).sort()
+
+    expect(menu.isVisible()).toEqual(true)
+    expect(menu_items_text).toEqual(['users.deactivateAccount'])
+
+    done()
+  })
+
+  it('shows for someone with users_delete privilege and shows proper entries', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeWithPrivilegesUsersDeleteNoRoles))
+    const wrapper = mount(Users, {
+      store,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    await flushPromises()
+    const menu = wrapper.findAll('.moderation-dropdown-menu').at(0)
+    const menu_items = menu.findAll('.el-dropdown-menu__item')
+    const menu_items_text = menu_items.wrappers.map(menu_item => menu_item.text()).sort()
+
+    expect(menu.isVisible()).toEqual(true)
+    expect(menu_items_text).toEqual(['users.deleteAccount'])
+
+    done()
+  })
+
+  it('shows for someone with users_manage_tags privilege and shows proper entries depending on wether tagpolicy is set', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeWithTagPolicyPrivilegesUsersManageTagsNoRoles))
+    const wrapper = mount(Users, {
+      store,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    await flushPromises()
+    const menu = wrapper.findAll('.moderation-dropdown-menu').at(0)
+    const menu_items = menu.findAll('.el-dropdown-menu__item')
+    const menu_items_text = menu_items.wrappers.map(menu_item => menu_item.text()).sort()
+
+    expect(menu.isVisible()).toEqual(true)
+    expect(menu_items_text).toEqual([
+      'users.disableAnySubscription',
+      'users.disableRemoteSubscription',
+      'users.forceNsfw',
+      'users.forceUnlisted',
+      'users.sandbox',
+      'users.stripMedia'
+    ])
+
+    store.state.users.mrfPolicies = []
+    await flushPromises()
+
+    expect(menu.findAll('.el-dropdown-menu__item').length).toEqual(0)
+
+    done()
+  })
+
+  it('shows enable tagpolicy for someone with users_manage_tags privilege and admin role when tagpolicy is not set', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeWithTagPolicyPrivilegesUsersManageTagsRolesAdmin))
+    const wrapper = mount(Users, {
+      store,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    await flushPromises()
+    const menu = wrapper.findAll('.moderation-dropdown-menu').at(0)
+    const menu_items = menu.findAll('.el-dropdown-menu__item')
+    const menu_items_text = menu_items.wrappers.map(menu_item => menu_item.text())
+
+    expect(menu.isVisible()).toEqual(true)
+    expect(menu_items_text.includes('users.disableAnySubscription')).toBe(true)
+    expect(menu_items_text.includes('users.disableRemoteSubscription')).toBe(true)
+    expect(menu_items_text.includes('users.forceNsfw')).toBe(true)
+    expect(menu_items_text.includes('users.forceUnlisted')).toBe(true)
+    expect(menu_items_text.includes('users.sandbox')).toBe(true)
+    expect(menu_items_text.includes('users.stripMedia')).toBe(true)
+
+    store.state.users.mrfPolicies = []
+    await flushPromises()
+
+    const menu_items_text_no_policy = menu.findAll('.el-dropdown-menu__item').wrappers.map(menu_item => menu_item.text())
+    expect(menu_items_text_no_policy.includes('users.disableAnySubscription')).toBe(false)
+    expect(menu_items_text_no_policy.includes('users.disableRemoteSubscription')).toBe(false)
+    expect(menu_items_text_no_policy.includes('users.forceNsfw')).toBe(false)
+    expect(menu_items_text_no_policy.includes('users.forceUnlisted')).toBe(false)
+    expect(menu_items_text_no_policy.includes('users.sandbox')).toBe(false)
+    expect(menu_items_text_no_policy.includes('users.stripMedia')).toBe(false)
+
+    expect(menu_items_text_no_policy.includes('users.enableTagPolicy')).toBe(true)
+
+    done()
+  })
+
+  it('shows for someone with users_manage_credentials privilege and shows proper entries', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeWithPrivilegesUsersManageCredentialsNoRoles))
+    const wrapper = mount(Users, {
+      store,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    await flushPromises()
+    const menu = wrapper.findAll('.moderation-dropdown-menu').at(0)
+    const menu_items = menu.findAll('.el-dropdown-menu__item')
+    const menu_items_text = menu_items.wrappers.map(menu_item => menu_item.text()).sort()
+
+    expect(menu.isVisible()).toEqual(true)
+    expect(menu_items_text).toEqual(['users.getPasswordResetToken'])
+
+    done()
+  })
+})
diff --git a/test/views/users/components/MultipleUsersMenu.test.js b/test/views/users/components/MultipleUsersMenu.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..70b1c6b1b74ab4fee5ddb345091f5f91c3a9563d
--- /dev/null
+++ b/test/views/users/components/MultipleUsersMenu.test.js
@@ -0,0 +1,200 @@
+import Vuex from 'vuex'
+import { mount, createLocalVue, config, RouterLinkStub } from '@vue/test-utils'
+import flushPromises from 'flush-promises'
+import Element from 'element-ui'
+import Users from '@/views/users/index'
+import {
+  storeNoPrivilegesNoRoles,
+  storeWithTagPolicyNoPrivilegesRolesAdmin,
+  storeWithPrivilegesUsersManageInvitesNoRoles,
+  storeWithPrivilegesUsersDeleteNoRoles,
+  storeWithPrivilegesUsersManageActivationStateNoRoles,
+  storeWithTagPolicyPrivilegesUsersManageTagsNoRoles,
+  storeWithTagPolicyPrivilegesUsersManageTagsRolesAdmin
+} from './store.conf'
+import { cloneDeep } from 'lodash'
+
+config.mocks["$t"] = (key) => key
+
+const localVue = createLocalVue()
+localVue.use(Vuex)
+localVue.use(Element)
+
+jest.mock('@/api/app')
+jest.mock('@/api/nodeInfo')
+jest.mock('@/api/users')
+jest.mock('@/api/settings')
+
+describe('The Multiple Users Moderation Menu', () => {
+  it('doesnt show for someone with no privileges and no roles', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeNoPrivilegesNoRoles))
+    const wrapper = mount(Users, {
+      store,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    await flushPromises()
+
+    expect(wrapper.find('.multiple-users-menu').exists()).toEqual(false)
+    done()
+  })
+
+  it('shows for someone with admin role and shows proper entries', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeWithTagPolicyNoPrivilegesRolesAdmin))
+    const wrapper = mount(Users, {
+      store,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    await flushPromises()
+    await wrapper.find('.el-table').findAll('input').at(1).setChecked()
+    const menu = wrapper.find('.multiple-users-menu')
+    const menu_items = menu.findAll('.el-dropdown-menu__item')
+    const menu_items_text = menu_items.wrappers.map(menu_item => menu_item.text()).sort()
+
+    expect(menu.isVisible()).toEqual(true)
+    expect(menu_items_text).toEqual([
+      'users.confirmAccounts',
+      'users.grantAdmin',
+      'users.grantModerator',
+      'users.requirePasswordReset',
+      'users.resendConfirmation',
+      'users.revokeAdmin',
+      'users.revokeModerator'
+    ])
+
+    store.state.users.mrfPolicies = []
+    await flushPromises()
+
+    expect(menu_items.length).toEqual(7)
+    done()
+  })
+
+  it('shows for someone with users_manage_invites privilege and shows proper entries', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeWithPrivilegesUsersManageInvitesNoRoles))
+    const wrapper = mount(Users, {
+      store,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    await flushPromises()
+    await wrapper.find('.el-table').findAll('input').at(1).setChecked()
+    const menu = wrapper.find('.multiple-users-menu')
+    const menu_items = menu.findAll('.el-dropdown-menu__item')
+    const menu_items_text = menu_items.wrappers.map(menu_item => menu_item.text())
+
+    expect(menu.isVisible()).toEqual(true)
+    expect(menu_items_text).toEqual(['users.approveAccounts'])
+    done()
+  })
+
+  it('shows for someone with users_delete privilege and shows proper entries', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeWithPrivilegesUsersDeleteNoRoles))
+    const wrapper = mount(Users, {
+      store,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    await flushPromises()
+    await wrapper.find('.el-table').findAll('input').at(1).setChecked()
+    const menu = wrapper.find('.multiple-users-menu')
+    const menu_items = menu.findAll('.el-dropdown-menu__item')
+    const menu_items_text = menu_items.wrappers.map(menu_item => menu_item.text()).sort()
+
+    expect(menu.isVisible()).toEqual(true)
+    expect(menu_items_text).toEqual(['users.deleteAccounts', 'users.rejectAccounts'])
+    done()
+  })
+
+  it('shows for someone with users_manage_activation_state privilege and shows proper entries', async (done) => {
+    const store = new Vuex.Store(cloneDeep(storeWithPrivilegesUsersManageActivationStateNoRoles))
+    const wrapper = mount(Users, {
+      store,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    await flushPromises()
+    await wrapper.find('.el-table').findAll('input').at(1).setChecked()
+    const menu = wrapper.find('.multiple-users-menu')
+    const menu_items = menu.findAll('.el-dropdown-menu__item')
+    const menu_items_text = menu_items.wrappers.map(menu_item => menu_item.text()).sort()
+
+    expect(menu.isVisible()).toEqual(true)
+    expect(menu_items_text).toEqual(['users.activateAccounts', 'users.deactivateAccounts'])
+    done()
+  })
+
+  it('shows for someone with users_manage_tags privilege and shows proper entries for non-admin/admin and with/without TagPolicy enabled', async (done) => {
+    const store_no_admin = new Vuex.Store(cloneDeep(storeWithTagPolicyPrivilegesUsersManageTagsNoRoles))
+    const wrapper_no_admin = mount(Users, {
+      store: store_no_admin,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+    const store_admin = new Vuex.Store(cloneDeep(storeWithTagPolicyPrivilegesUsersManageTagsRolesAdmin))
+    const wrapper_admin = mount(Users, {
+      store: store_admin,
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+
+    await flushPromises()
+    await wrapper_no_admin.find('.el-table').findAll('input').at(1).setChecked()
+    await wrapper_admin.find('.el-table').findAll('input').at(1).setChecked()
+    const menu_no_admin = wrapper_no_admin.find('.multiple-users-menu')
+    const menu_admin = wrapper_admin.find('.multiple-users-menu')
+    const menu_no_admin_items = menu_no_admin.findAll('.el-dropdown-menu__item')
+    const menu_admin_items = menu_admin.findAll('.el-dropdown-menu__item')
+    const filter = menu_item => { return menu_item.find('.tag-container .tag-text').exists() && menu_item.find('.tag-container .tag-text').text() }
+    const menu_no_admin_items_text = menu_no_admin_items.wrappers.map(filter).sort()
+    const menu_admin_items_text = menu_admin_items.wrappers.map(filter)
+
+    expect(menu_no_admin.isVisible()).toEqual(true)
+    expect(menu_no_admin_items_text).toEqual([
+      'users.disableAnySubscriptionForMultiple',
+      'users.disableRemoteSubscriptionForMultiple',
+      'users.forceNsfw',
+      'users.forceUnlisted',
+      'users.sandbox',
+      'users.stripMedia'
+    ])
+
+    expect(menu_admin.isVisible()).toEqual(true)
+    expect(menu_admin_items_text.includes('users.forceNsfw')).toBe(true)
+    expect(menu_admin_items_text.includes('users.stripMedia')).toBe(true)
+    expect(menu_admin_items_text.includes('users.forceUnlisted')).toBe(true)
+    expect(menu_admin_items_text.includes('users.sandbox')).toBe(true)
+    expect(menu_admin_items_text.includes('users.disableRemoteSubscriptionForMultiple')).toBe(true)
+    expect(menu_admin_items_text.includes('users.disableAnySubscriptionForMultiple')).toBe(true)
+
+    store_no_admin.state.users.mrfPolicies = []
+    store_admin.state.users.mrfPolicies = []
+    await flushPromises()
+
+    // Only an admin with users_manage_tags privilege can enable TagPolicy from the menu
+    expect(menu_no_admin.findAll('.el-dropdown-menu__item').length).toEqual(0)
+    expect(menu_admin.findAll('.el-dropdown-menu__item').wrappers.map(wrapper => wrapper.text()).includes('users.enableTagPolicy')).toBe(true)
+    done()
+  })
+})
diff --git a/test/views/users/components/store.conf.js b/test/views/users/components/store.conf.js
new file mode 100644
index 0000000000000000000000000000000000000000..1a084353bcd37bd689e655e20d261be008bbfcbc
--- /dev/null
+++ b/test/views/users/components/store.conf.js
@@ -0,0 +1,150 @@
+import app from '@/store/modules/app'
+import settings from '@/store/modules/settings'
+import user from '@/store/modules/user'
+import userProfile from '@/store/modules/userProfile'
+import users from '@/store/modules/users'
+import getters from '@/store/getters'
+
+export const storeNoPrivilegesNoRoles = {
+  modules: {
+    app,
+    settings,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: [],
+        privileges: []
+      }
+    },
+    userProfile,
+    users
+  },
+  getters
+}
+
+export const storeWithTagPolicyNoPrivilegesRolesAdmin = {
+  modules: {
+    app,
+    settings,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: ['admin'],
+        privileges: []
+      }
+    },
+    userProfile,
+    users: { ...users, state: { ...users.state, mrfPolicies: ['Pleroma.Web.ActivityPub.MRF.TagPolicy'] }}
+  },
+  getters
+}
+
+export const storeWithPrivilegesUsersManageInvitesNoRoles = {
+  modules: {
+    app,
+    settings,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: [],
+        privileges: ['users_manage_invites']
+      }
+    },
+    userProfile,
+    users
+  },
+  getters
+}
+
+export const storeWithPrivilegesUsersDeleteNoRoles = {
+  modules: {
+    app,
+    settings,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: [],
+        privileges: ['users_delete']
+      }
+    },
+    userProfile,
+    users
+  },
+  getters
+}
+
+export const storeWithPrivilegesUsersManageActivationStateNoRoles = {
+  modules: {
+    app,
+    settings,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: [],
+        privileges: ['users_manage_activation_state']
+      }
+    },
+    userProfile,
+    users
+  },
+  getters
+}
+
+export const storeWithTagPolicyPrivilegesUsersManageTagsNoRoles = {
+  modules: {
+    app,
+    settings,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: [],
+        privileges: ['users_manage_tags']
+      }
+    },
+    userProfile,
+    users: { ...users, state: { ...users.state, mrfPolicies: ['Pleroma.Web.ActivityPub.MRF.TagPolicy'] }}
+  },
+  getters
+}
+
+export const storeWithTagPolicyPrivilegesUsersManageTagsRolesAdmin = {
+  modules: {
+    app,
+    settings,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: ['admin'],
+        privileges: ['users_manage_tags']
+      }
+    },
+    userProfile,
+    users: { ...users, state: { ...users.state, mrfPolicies: ['Pleroma.Web.ActivityPub.MRF.TagPolicy'] }}
+  },
+  getters
+}
+
+export const storeWithPrivilegesUsersManageCredentialsNoRoles = {
+  modules: {
+    app,
+    settings,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: [],
+        privileges: ['users_manage_credentials']
+      }
+    },
+    userProfile,
+    users
+  },
+  getters
+}
diff --git a/test/views/users/index.test.js b/test/views/users/index.test.js
index 8c486cdf432e9cf0bbbfa071239a9f4894624475..195282998587a7a501f5cdee14da46b560f2616c 100644
--- a/test/views/users/index.test.js
+++ b/test/views/users/index.test.js
@@ -4,7 +4,11 @@ import flushPromises from 'flush-promises'
 import Element from 'element-ui'
 import Users from '@/views/users/index'
 import NewAccountDialog from '@/views/users/components/NewAccountDialog'
-import { storeConfig } from './store.conf'
+import {
+  storeConfig,
+  storeWithRoleAdminNoPrivileges,
+  storeWithNoRolesNoPrivileges
+} from './store.conf'
 import { cloneDeep } from 'lodash'
 
 config.mocks["$t"] = () => {}
@@ -82,6 +86,32 @@ describe('Users actions', () => {
     store = new Vuex.Store(cloneDeep(storeConfig))
   })
 
+  it('doesnt show create new account button if not privileged', async (done) => {
+    const wrapper_admin = mount(Users, {
+      store: new Vuex.Store(cloneDeep(storeWithRoleAdminNoPrivileges)),
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+
+    const wrapper_no_admin = mount(Users, {
+      store: new Vuex.Store(cloneDeep(storeWithNoRolesNoPrivileges)),
+      localVue,
+      sync: false,
+      stubs: {
+        RouterLink: RouterLinkStub
+      }
+    })
+
+    await flushPromises()
+    expect(wrapper_admin.find('.actions-button').isVisible()).toBe(true)
+    expect(wrapper_no_admin.find('.actions-button').exists()).toBe(false)
+
+    done()
+  })
+
   it('grants admin right to a local user', async (done) => {
     const wrapper = mount(Users, {
       store,
diff --git a/test/views/users/store.conf.js b/test/views/users/store.conf.js
index 7edf286535d4c5156bc9defafb8b447bac9d35cc..6a7736ceced02d8e66f9485027234d27d8d24b3a 100644
--- a/test/views/users/store.conf.js
+++ b/test/views/users/store.conf.js
@@ -9,7 +9,14 @@ export const storeConfig = {
   modules: {
     app,
     settings,
-    user,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: ['admin'],
+        privileges: ['users_manage_activation_state', 'users_delete', 'users_manage_tags', 'users_manage_credentials']
+      }
+    },
     userProfile,
     users
   },
@@ -20,9 +27,59 @@ export const storeWithTagPolicy = {
   modules: {
     app,
     settings,
-    user,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: ['admin'],
+        privileges: ['users_manage_activation_state', 'users_delete', 'users_manage_tags', 'users_manage_credentials']
+      }
+    },
     userProfile,
-    users: { ...users, state: { ...users.state, mrfPolicies: ['Pleroma.Web.ActivityPub.MRF.TagPolicy'] }}
+    users: {
+      ...users,
+      state: {
+        ...users.state,
+        mrfPolicies: ['Pleroma.Web.ActivityPub.MRF.TagPolicy']
+      }
+    }
+  },
+  getters
+}
+
+export const storeWithRoleAdminNoPrivileges = {
+  modules: {
+    app,
+    settings,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: ['admin'],
+        privileges: []
+      }
+    },
+    userProfile,
+    users
+  },
+  getters
+}
+
+
+export const storeWithNoRolesNoPrivileges = {
+  modules: {
+    app,
+    settings,
+    user: {
+      ...user,
+      state: {
+        ...user.state,
+        roles: [],
+        privileges: []
+      }
+    },
+    userProfile,
+    users
   },
   getters
 }