diff --git a/api/auth/groupauth.py b/api/auth/groupauth.py
index df66e8241a617372213cff4cb937955aeab31b61..5cea975ed1c640684bd9e26b8ce0b3ef6607fecc 100644
--- a/api/auth/groupauth.py
+++ b/api/auth/groupauth.py
@@ -11,8 +11,6 @@ def default(handler, group=None):
                 pass
             elif handler.public_request:
                 handler.abort(400, 'public request is not valid')
-            elif config.db.users.find_one({'_id': handler.uid}).get('root'):
-                pass
             elif method in ['DELETE', 'POST']:
                 handler.abort(403, 'not allowed to perform operation')
             elif _get_access(handler.uid, group) >= INTEGER_ROLES['admin']:
diff --git a/api/auth/userauth.py b/api/auth/userauth.py
index 13cc7b3a838a802e2403ecb1786db7f10ef4e19e..c69870faa4df6f0d4fa6bfb20c83fd22a540bfcd 100644
--- a/api/auth/userauth.py
+++ b/api/auth/userauth.py
@@ -5,6 +5,8 @@ def default(handler, user=None):
                 handler.abort(403, 'public request is not authorized')
             elif handler.superuser_request and not (method == 'DELETE' and _id == handler.uid):
                 pass
+            elif handler.user_is_admin and (method == 'DELETE' and not _id == handler.uid):
+                pass
             elif method == 'PUT' and handler.uid == _id:
                 if 'root' in payload and payload['root'] != user['root']:
                     handler.abort(400, 'user cannot alter own superuser privilege')
@@ -12,11 +14,13 @@ def default(handler, user=None):
                     handler.abort(400, 'user cannot alter own disabled status')
                 else:
                     pass
-            elif method == 'POST' and not handler.superuser_request:
+            elif method == 'PUT' and handler.user_is_admin:
+                pass
+            elif method == 'POST' and not handler.superuser_request and not handler.user_is_admin:
                 handler.abort(403, 'only superuser are allowed to create users')
-            elif method == 'POST' and handler.superuser_request:
+            elif method == 'POST' and (handler.superuser_request or handler.user_is_admin):
                 pass
-            elif method == 'GET' and _id == handler.uid:
+            elif method == 'GET':
                 pass
             else:
                 handler.abort(403, 'not allowed to perform operation')
diff --git a/api/jobs/handlers.py b/api/jobs/handlers.py
index 2a9b50f3ba15749f309b15b8d3ac8437469a10d7..237b097f0074e732f40068fecea82c980979cce1 100644
--- a/api/jobs/handlers.py
+++ b/api/jobs/handlers.py
@@ -226,6 +226,12 @@ class RuleHandler(base.RequestHandler):
 
 class JobsHandler(base.RequestHandler):
     """Provide /jobs API routes."""
+    def get(self):
+        """List all jobs."""
+        user = config.db.users.find_one({'_id': self.uid})
+        if not self.superuser_request and not user.get('root'):
+            self.abort(403, 'Request requires superuser')
+        return list(config.db.jobs.find())
 
     def add(self):
         """Add a job to the queue."""
@@ -282,7 +288,8 @@ class JobsHandler(base.RequestHandler):
         return { '_id': result }
 
     def stats(self):
-        if not self.superuser_request:
+        user = config.db.users.find_one({'_id': self.uid})
+        if not self.superuser_request and not user.get('root'):
             self.abort(403, 'Request requires superuser')
 
         return Queue.get_statistics()
@@ -306,7 +313,8 @@ class JobsHandler(base.RequestHandler):
             return job
 
     def reap_stale(self):
-        if not self.superuser_request:
+        user = config.db.users.find_one({'_id': self.uid})
+        if not self.superuser_request and not user.get('root'):
             self.abort(403, 'Request requires superuser')
 
         count = Queue.scan_for_orphans()
@@ -352,7 +360,7 @@ class JobHandler(base.RequestHandler):
         mutation = self.request.json
 
         # If user is not superuser, can only cancel jobs they spawned
-        if not self.superuser_request:
+        if not self.superuser_request and not self.user_is_admin:
             if j.origin.get('id') != self.uid:
                 raise APIPermissionException('User does not have permission to access job {}'.format(_id))
             if mutation != {'state': 'cancelled'}:
diff --git a/test/integration_tests/python/test_jobs.py b/test/integration_tests/python/test_jobs.py
index b1bee5baa26339b8ab4d52217c146ca87464d5bf..eeb64e44774363bed5908016274a1e1458991969 100644
--- a/test/integration_tests/python/test_jobs.py
+++ b/test/integration_tests/python/test_jobs.py
@@ -126,8 +126,8 @@ def test_jobs(data_builder, as_user, as_admin, as_root):
     r = as_root.post('/jobs/' + next_job_id + '/retry')
     assert r.ok
 
-    # get next job
-    r = as_root.get('/jobs/next', params={'tags': 'test-tag'})
+    # get next job as admin
+    r = as_admin.get('/jobs/next', params={'tags': 'test-tag'})
     assert r.ok
     next_job_id = r.json()['id']
 
diff --git a/test/integration_tests/python/test_users.py b/test/integration_tests/python/test_users.py
index 6137439c0b85dbbb559fc18ab6159016c5d0abd5..18bf61fcfcb803682fa57b044d9671dacb078116 100644
--- a/test/integration_tests/python/test_users.py
+++ b/test/integration_tests/python/test_users.py
@@ -1,4 +1,4 @@
-def test_users(as_root, as_user, as_public):
+def test_users(as_root, as_admin, as_user, as_public):
     # List users
     r = as_user.get('/users')
     assert r.ok
@@ -50,6 +50,21 @@ def test_users(as_root, as_user, as_public):
     r = as_root.get('/users/' + new_user_id)
     assert r.ok
 
+    # Add new user as admin
+    new_user_id_admin = 'new2@user.com'
+    r = as_admin.post('/users', json={
+        '_id': new_user_id_admin,
+        'firstname': 'New2',
+        'lastname': 'User2',
+    })
+    assert r.ok
+    r = as_root.get('/users/' + new_user_id)
+    assert r.ok
+
+    #Get another user as user
+    r = as_user.get('/users/' + new_user_id)
+    assert r.ok
+
     # Try to update non-existent user
     r = as_root.put('/users/nonexistent@user.com', json={'firstname': 'Realname'})
     assert r.status_code == 404
@@ -59,6 +74,11 @@ def test_users(as_root, as_user, as_public):
     assert r.ok
     assert r.json()['modified'] == 1
 
+    # Update existing user as admin
+    r = as_admin.put('/users/' + new_user_id_admin, json={'firstname': 'Realname2'})
+    assert r.ok
+    assert r.json()['modified'] == 1
+
     # Try to delete non-existent user
     r = as_root.delete('/users/nonexistent@user.com')
     assert r.status_code == 404
@@ -67,6 +87,10 @@ def test_users(as_root, as_user, as_public):
     r = as_root.delete('/users/' + new_user_id)
     assert r.ok
 
+    # Delete user
+    r = as_admin.delete('/users/' + new_user_id_admin)
+    assert r.ok
+
     # Test HTTPS enforcement on avatar urls
     new_user_id = 'new@user.com'
     r = as_root.post('/users', json={