diff --git a/CHANGELOG.md b/CHANGELOG.md
index e3ccfa4ea..24876d3f2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Metadata Link: Atom syndication Feed
 - Mix task to re-count statuses for all users (`mix pleroma.count_statuses`)
 - Mastodon API: Add `exclude_visibilities` parameter to the timeline and notification endpoints
+- Admin API: `/users/:nickname/toggle_activation` endpoint is now deprecated in favor of: `/users/activate`, `/users/deactivate`, both accept `nicknames` array
+- Admin API: `POST/DELETE /api/pleroma/admin/users/:nickname/permission_group/:permission_group` are deprecated in favor of: `POST/DELETE /api/pleroma/admin/users/permission_group/:permission_group` (both accept `nicknames` array), `DELETE /api/pleroma/admin/users` (`nickname` query param or `nickname` sent in JSON body) is deprecated in favor of: `DELETE /api/pleroma/admin/users` (`nicknames` query array param or `nicknames` sent in JSON body).
 
 ### Changed
 - **Breaking:** Elixir >=1.8 is now required (was >= 1.7)
diff --git a/docs/API/admin_api.md b/docs/API/admin_api.md
index ee9e68cb1..60755e40a 100644
--- a/docs/API/admin_api.md
+++ b/docs/API/admin_api.md
@@ -47,7 +47,7 @@ Authentication is required and the user must be an admin.
 }
 ```
 
-## `/api/pleroma/admin/users`
+## DEPRECATED `DELETE /api/pleroma/admin/users`
 
 ### Remove a user
 
@@ -56,6 +56,15 @@ Authentication is required and the user must be an admin.
   - `nickname`
 - Response: User’s nickname
 
+## `DELETE /api/pleroma/admin/users`
+
+### Remove a user
+
+- Method `DELETE`
+- Params:
+  - `nicknames`
+- Response: Array of user nicknames
+
 ### Create a user
 
 - Method: `POST`
@@ -154,28 +163,86 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
 }
 ```
 
-### Add user in permission group
+## DEPRECATED `POST /api/pleroma/admin/users/:nickname/permission_group/:permission_group`
+
+### Add user to permission group
 
-- Method: `POST`
 - Params: none
 - Response:
   - On failure: `{"error": "…"}`
   - On success: JSON of the `user.info`
 
+## `POST /api/pleroma/admin/users/permission_group/:permission_group`
+
+### Add users to permission group
+
+- Params:
+  - `nicknames`: nicknames array
+- Response:
+  - On failure: `{"error": "…"}`
+  - On success: JSON of the `user.info`
+
+## DEPRECATED `DELETE /api/pleroma/admin/users/:nickname/permission_group/:permission_group`
+
 ### Remove user from permission group
 
-- Method: `DELETE`
 - Params: none
 - Response:
   - On failure: `{"error": "…"}`
   - On success: JSON of the `user.info`
 - Note: An admin cannot revoke their own admin status.
 
-## `/api/pleroma/admin/users/:nickname/activation_status`
+## `DELETE /api/pleroma/admin/users/permission_group/:permission_group`
+
+### Remove users from permission group
+
+- Params:
+  - `nicknames`: nicknames array
+- Response:
+  - On failure: `{"error": "…"}`
+  - On success: JSON of the `user.info`
+- Note: An admin cannot revoke their own admin status.
+
+## `PATCH /api/pleroma/admin/users/activate`
+
+### Activate user
+
+- Params:
+  - `nicknames`: nicknames array
+- Response:
+
+```json
+{
+  users: [
+    {
+      // user object
+    }
+  ]
+}
+```
+
+## `PATCH /api/pleroma/admin/users/deactivate`
+
+### Deactivate user
+
+- Params:
+  - `nicknames`: nicknames array
+- Response:
+
+```json
+{
+  users: [
+    {
+      // user object
+    }
+  ]
+}
+```
+
+## DEPRECATED `PATCH /api/pleroma/admin/users/:nickname/activation_status`
 
 ### Active or deactivate a user
 
-- Method: `PUT`
 - Params:
   - `nickname`
   - `status` BOOLEAN field, false value means deactivation.
diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex
index 352cad433..e8884e6e8 100644
--- a/lib/pleroma/moderation_log.ex
+++ b/lib/pleroma/moderation_log.ex
@@ -86,18 +86,18 @@ defp parse_datetime(datetime) do
     parsed_datetime
   end
 
-  @spec insert_log(%{actor: User, subject: User, action: String.t(), permission: String.t()}) ::
+  @spec insert_log(%{actor: User, subject: [User], action: String.t(), permission: String.t()}) ::
           {:ok, ModerationLog} | {:error, any}
   def insert_log(%{
         actor: %User{} = actor,
-        subject: %User{} = subject,
+        subject: subjects,
         action: action,
         permission: permission
       }) do
     %ModerationLog{
       data: %{
         "actor" => user_to_map(actor),
-        "subject" => user_to_map(subject),
+        "subject" => user_to_map(subjects),
         "action" => action,
         "permission" => permission,
         "message" => ""
@@ -303,13 +303,16 @@ def insert_log(%{
   end
 
   @spec insert_log_entry_with_message(ModerationLog) :: {:ok, ModerationLog} | {:error, any}
-
   defp insert_log_entry_with_message(entry) do
     entry.data["message"]
     |> put_in(get_log_entry_message(entry))
     |> Repo.insert()
   end
 
+  defp user_to_map(users) when is_list(users) do
+    users |> Enum.map(&user_to_map/1)
+  end
+
   defp user_to_map(%User{} = user) do
     user
     |> Map.from_struct()
@@ -349,10 +352,10 @@ def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
           "action" => "delete",
-          "subject" => %{"nickname" => subject_nickname, "type" => "user"}
+          "subject" => subjects
         }
       }) do
-    "@#{actor_nickname} deleted user @#{subject_nickname}"
+    "@#{actor_nickname} deleted users: #{users_to_nicknames_string(subjects)}"
   end
 
   @spec get_log_entry_message(ModerationLog) :: String.t()
@@ -363,12 +366,7 @@ def get_log_entry_message(%ModerationLog{
           "subjects" => subjects
         }
       }) do
-    nicknames =
-      subjects
-      |> Enum.map(&"@#{&1["nickname"]}")
-      |> Enum.join(", ")
-
-    "@#{actor_nickname} created users: #{nicknames}"
+    "@#{actor_nickname} created users: #{users_to_nicknames_string(subjects)}"
   end
 
   @spec get_log_entry_message(ModerationLog) :: String.t()
@@ -376,10 +374,10 @@ def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
           "action" => "activate",
-          "subject" => %{"nickname" => subject_nickname, "type" => "user"}
+          "subject" => users
         }
       }) do
-    "@#{actor_nickname} activated user @#{subject_nickname}"
+    "@#{actor_nickname} activated users: #{users_to_nicknames_string(users)}"
   end
 
   @spec get_log_entry_message(ModerationLog) :: String.t()
@@ -387,10 +385,10 @@ def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
           "action" => "deactivate",
-          "subject" => %{"nickname" => subject_nickname, "type" => "user"}
+          "subject" => users
         }
       }) do
-    "@#{actor_nickname} deactivated user @#{subject_nickname}"
+    "@#{actor_nickname} deactivated users: #{users_to_nicknames_string(users)}"
   end
 
   @spec get_log_entry_message(ModerationLog) :: String.t()
@@ -402,14 +400,9 @@ def get_log_entry_message(%ModerationLog{
           "action" => "tag"
         }
       }) do
-    nicknames_string =
-      nicknames
-      |> Enum.map(&"@#{&1}")
-      |> Enum.join(", ")
-
     tags_string = tags |> Enum.join(", ")
 
-    "@#{actor_nickname} added tags: #{tags_string} to users: #{nicknames_string}"
+    "@#{actor_nickname} added tags: #{tags_string} to users: #{nicknames_to_string(nicknames)}"
   end
 
   @spec get_log_entry_message(ModerationLog) :: String.t()
@@ -421,14 +414,9 @@ def get_log_entry_message(%ModerationLog{
           "action" => "untag"
         }
       }) do
-    nicknames_string =
-      nicknames
-      |> Enum.map(&"@#{&1}")
-      |> Enum.join(", ")
-
     tags_string = tags |> Enum.join(", ")
 
-    "@#{actor_nickname} removed tags: #{tags_string} from users: #{nicknames_string}"
+    "@#{actor_nickname} removed tags: #{tags_string} from users: #{nicknames_to_string(nicknames)}"
   end
 
   @spec get_log_entry_message(ModerationLog) :: String.t()
@@ -436,11 +424,11 @@ def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
           "action" => "grant",
-          "subject" => %{"nickname" => subject_nickname},
+          "subject" => users,
           "permission" => permission
         }
       }) do
-    "@#{actor_nickname} made @#{subject_nickname} #{permission}"
+    "@#{actor_nickname} made #{users_to_nicknames_string(users)} #{permission}"
   end
 
   @spec get_log_entry_message(ModerationLog) :: String.t()
@@ -448,11 +436,11 @@ def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
           "action" => "revoke",
-          "subject" => %{"nickname" => subject_nickname},
+          "subject" => users,
           "permission" => permission
         }
       }) do
-    "@#{actor_nickname} revoked #{permission} role from @#{subject_nickname}"
+    "@#{actor_nickname} revoked #{permission} role from #{users_to_nicknames_string(users)}"
   end
 
   @spec get_log_entry_message(ModerationLog) :: String.t()
@@ -551,4 +539,16 @@ def get_log_entry_message(%ModerationLog{
       }) do
     "@#{actor_nickname} deleted status ##{subject_id}"
   end
+
+  defp nicknames_to_string(nicknames) do
+    nicknames
+    |> Enum.map(&"@#{&1}")
+    |> Enum.join(", ")
+  end
+
+  defp users_to_nicknames_string(users) do
+    users
+    |> Enum.map(&"@#{&1["nickname"]}")
+    |> Enum.join(", ")
+  end
 end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 1e055014e..917bcf2ef 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1061,7 +1061,15 @@ def deactivate_async(user, status \\ true) do
     BackgroundWorker.enqueue("deactivate_user", %{"user_id" => user.id, "status" => status})
   end
 
-  def deactivate(%User{} = user, status \\ true) do
+  def deactivate(user, status \\ true)
+
+  def deactivate(users, status) when is_list(users) do
+    Repo.transaction(fn ->
+      for user <- users, do: deactivate(user, status)
+    end)
+  end
+
+  def deactivate(%User{} = user, status) do
     with {:ok, user} <- update_info(user, &User.Info.set_activation_status(&1, status)) do
       Enum.each(get_followers(user), &invalidate_cache/1)
       Enum.each(get_friends(user), &update_follower_count/1)
@@ -1074,6 +1082,10 @@ def update_notification_settings(%User{} = user, settings \\ %{}) do
     update_info(user, &User.Info.update_notification_settings(&1, settings))
   end
 
+  def delete(users) when is_list(users) do
+    for user <- users, do: delete(user)
+  end
+
   def delete(%User{} = user) do
     BackgroundWorker.enqueue("delete_user", %{"user_id" => user.id})
   end
@@ -1627,6 +1639,12 @@ def change_info(user, fun) do
 
   `fun` is called with the `user.info`.
   """
+  def update_info(users, fun) when is_list(users) do
+    Repo.transaction(fn ->
+      for user <- users, do: update_info(user, fun)
+    end)
+  end
+
   def update_info(user, fun) do
     user
     |> change_info(fun)
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 513bae800..ab0d0fe0a 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -46,6 +46,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
            :user_delete,
            :users_create,
            :user_toggle_activation,
+           :user_activate,
+           :user_deactivate,
            :tag_users,
            :untag_users,
            :right_add,
@@ -98,7 +100,7 @@ def user_delete(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
 
     ModerationLog.insert_log(%{
       actor: admin,
-      subject: user,
+      subject: [user],
       action: "delete"
     })
 
@@ -106,6 +108,20 @@ def user_delete(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
     |> json(nickname)
   end
 
+  def user_delete(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
+    users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
+    User.delete(users)
+
+    ModerationLog.insert_log(%{
+      actor: admin,
+      subject: users,
+      action: "delete"
+    })
+
+    conn
+    |> json(nicknames)
+  end
+
   def user_follow(%{assigns: %{user: admin}} = conn, %{
         "follower" => follower_nick,
         "followed" => followed_nick
@@ -240,7 +256,7 @@ def user_toggle_activation(%{assigns: %{user: admin}} = conn, %{"nickname" => ni
 
     ModerationLog.insert_log(%{
       actor: admin,
-      subject: user,
+      subject: [user],
       action: action
     })
 
@@ -249,6 +265,36 @@ def user_toggle_activation(%{assigns: %{user: admin}} = conn, %{"nickname" => ni
     |> render("show.json", %{user: updated_user})
   end
 
+  def user_activate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
+    users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
+    {:ok, updated_users} = User.deactivate(users, false)
+
+    ModerationLog.insert_log(%{
+      actor: admin,
+      subject: users,
+      action: "activate"
+    })
+
+    conn
+    |> put_view(AccountView)
+    |> render("index.json", %{users: Keyword.values(updated_users)})
+  end
+
+  def user_deactivate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
+    users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
+    {:ok, updated_users} = User.deactivate(users, true)
+
+    ModerationLog.insert_log(%{
+      actor: admin,
+      subject: users,
+      action: "deactivate"
+    })
+
+    conn
+    |> put_view(AccountView)
+    |> render("index.json", %{users: Keyword.values(updated_users)})
+  end
+
   def tag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
     with {:ok, _} <- User.tag(nicknames, tags) do
       ModerationLog.insert_log(%{
@@ -313,6 +359,31 @@ defp maybe_parse_filters(filters) do
     |> Enum.into(%{}, &{&1, true})
   end
 
+  def right_add_multiple(%{assigns: %{user: admin}} = conn, %{
+        "permission_group" => permission_group,
+        "nicknames" => nicknames
+      })
+      when permission_group in ["moderator", "admin"] do
+    info = Map.put(%{}, "is_" <> permission_group, true)
+
+    users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
+
+    User.update_info(users, &User.Info.admin_api_update(&1, info))
+
+    ModerationLog.insert_log(%{
+      action: "grant",
+      actor: admin,
+      subject: users,
+      permission: permission_group
+    })
+
+    json(conn, info)
+  end
+
+  def right_add_multiple(conn, _) do
+    render_error(conn, :not_found, "No such permission_group")
+  end
+
   def right_add(%{assigns: %{user: admin}} = conn, %{
         "permission_group" => permission_group,
         "nickname" => nickname
@@ -328,7 +399,7 @@ def right_add(%{assigns: %{user: admin}} = conn, %{
     ModerationLog.insert_log(%{
       action: "grant",
       actor: admin,
-      subject: user,
+      subject: [user],
       permission: permission_group
     })
 
@@ -349,8 +420,36 @@ def right_get(conn, %{"nickname" => nickname}) do
     })
   end
 
-  def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" => nickname}) do
-    render_error(conn, :forbidden, "You can't revoke your own admin status.")
+  def right_delete_multiple(
+        %{assigns: %{user: %{nickname: admin_nickname} = admin}} = conn,
+        %{
+          "permission_group" => permission_group,
+          "nicknames" => nicknames
+        }
+      )
+      when permission_group in ["moderator", "admin"] do
+    with false <- Enum.member?(nicknames, admin_nickname) do
+      info = Map.put(%{}, "is_" <> permission_group, false)
+
+      users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
+
+      User.update_info(users, &User.Info.admin_api_update(&1, info))
+
+      ModerationLog.insert_log(%{
+        action: "revoke",
+        actor: admin,
+        subject: users,
+        permission: permission_group
+      })
+
+      json(conn, info)
+    else
+      _ -> render_error(conn, :forbidden, "You can't revoke your own admin/moderator status.")
+    end
+  end
+
+  def right_delete_multiple(conn, _) do
+    render_error(conn, :not_found, "No such permission_group")
   end
 
   def right_delete(
@@ -371,34 +470,15 @@ def right_delete(
     ModerationLog.insert_log(%{
       action: "revoke",
       actor: admin,
-      subject: user,
+      subject: [user],
       permission: permission_group
     })
 
     json(conn, info)
   end
 
-  def right_delete(conn, _) do
-    render_error(conn, :not_found, "No such permission_group")
-  end
-
-  def set_activation_status(%{assigns: %{user: admin}} = conn, %{
-        "nickname" => nickname,
-        "status" => status
-      }) do
-    with {:ok, status} <- Ecto.Type.cast(:boolean, status),
-         %User{} = user <- User.get_cached_by_nickname(nickname),
-         {:ok, _} <- User.deactivate(user, !status) do
-      action = if(user.info.deactivated, do: "activate", else: "deactivate")
-
-      ModerationLog.insert_log(%{
-        actor: admin,
-        subject: user,
-        action: action
-      })
-
-      json_response(conn, :no_content, "")
-    end
+  def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" => nickname}) do
+    render_error(conn, :forbidden, "You can't revoke your own admin status.")
   end
 
   def relay_follow(%{assigns: %{user: admin}} = conn, %{"relay_url" => target}) do
diff --git a/lib/pleroma/web/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex
index a96affd40..441269162 100644
--- a/lib/pleroma/web/admin_api/views/account_view.ex
+++ b/lib/pleroma/web/admin_api/views/account_view.ex
@@ -19,6 +19,12 @@ def render("index.json", %{users: users, count: count, page_size: page_size}) do
     }
   end
 
+  def render("index.json", %{users: users}) do
+    %{
+      users: render_many(users, AccountView, "show.json", as: :user)
+    }
+  end
+
   def render("show.json", %{user: user}) do
     avatar = User.avatar_url(user) |> MediaProxy.url()
     display_name = HTML.strip_tags(user.name || user.nickname)
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index ae799b8ac..80651f3ff 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -137,11 +137,14 @@ defmodule Pleroma.Web.Router do
     delete("/users", AdminAPIController, :user_delete)
     post("/users", AdminAPIController, :users_create)
     patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation)
+    patch("/users/activate", AdminAPIController, :user_activate)
+    patch("/users/deactivate", AdminAPIController, :user_deactivate)
     put("/users/tag", AdminAPIController, :tag_users)
     delete("/users/tag", AdminAPIController, :untag_users)
 
     get("/users/:nickname/permission_group", AdminAPIController, :right_get)
     get("/users/:nickname/permission_group/:permission_group", AdminAPIController, :right_get)
+
     post("/users/:nickname/permission_group/:permission_group", AdminAPIController, :right_add)
 
     delete(
@@ -150,7 +153,13 @@ defmodule Pleroma.Web.Router do
       :right_delete
     )
 
-    put("/users/:nickname/activation_status", AdminAPIController, :set_activation_status)
+    post("/users/permission_group/:permission_group", AdminAPIController, :right_add_multiple)
+
+    delete(
+      "/users/permission_group/:permission_group",
+      AdminAPIController,
+      :right_delete_multiple
+    )
 
     post("/relay", AdminAPIController, :relay_follow)
     delete("/relay", AdminAPIController, :relay_unfollow)
diff --git a/test/moderation_log_test.exs b/test/moderation_log_test.exs
index a39a00e02..81c0fef12 100644
--- a/test/moderation_log_test.exs
+++ b/test/moderation_log_test.exs
@@ -24,13 +24,13 @@ test "logging user deletion by moderator", %{moderator: moderator, subject1: sub
       {:ok, _} =
         ModerationLog.insert_log(%{
           actor: moderator,
-          subject: subject1,
+          subject: [subject1],
           action: "delete"
         })
 
       log = Repo.one(ModerationLog)
 
-      assert log.data["message"] == "@#{moderator.nickname} deleted user @#{subject1.nickname}"
+      assert log.data["message"] == "@#{moderator.nickname} deleted users: @#{subject1.nickname}"
     end
 
     test "logging user creation by moderator", %{
@@ -128,7 +128,7 @@ test "logging user grant by moderator", %{moderator: moderator, subject1: subjec
       {:ok, _} =
         ModerationLog.insert_log(%{
           actor: moderator,
-          subject: subject1,
+          subject: [subject1],
           action: "grant",
           permission: "moderator"
         })
@@ -142,7 +142,7 @@ test "logging user revoke by moderator", %{moderator: moderator, subject1: subje
       {:ok, _} =
         ModerationLog.insert_log(%{
           actor: moderator,
-          subject: subject1,
+          subject: [subject1],
           action: "revoke",
           permission: "moderator"
         })
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index b5c355e66..645b79f57 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -17,8 +17,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
   alias Pleroma.Web.MediaProxy
   import Pleroma.Factory
 
-  describe "/api/pleroma/admin/users" do
-    test "Delete" do
+  describe "DELETE /api/pleroma/admin/users" do
+    test "single user" do
       admin = insert(:user, info: %{is_admin: true})
       user = insert(:user)
 
@@ -30,15 +30,36 @@ test "Delete" do
 
       log_entry = Repo.one(ModerationLog)
 
-      assert log_entry.data["subject"]["nickname"] == user.nickname
-      assert log_entry.data["action"] == "delete"
-
       assert ModerationLog.get_log_entry_message(log_entry) ==
-               "@#{admin.nickname} deleted user @#{user.nickname}"
+               "@#{admin.nickname} deleted users: @#{user.nickname}"
 
       assert json_response(conn, 200) == user.nickname
     end
 
+    test "multiple users" do
+      admin = insert(:user, info: %{is_admin: true})
+      user_one = insert(:user)
+      user_two = insert(:user)
+
+      conn =
+        build_conn()
+        |> assign(:user, admin)
+        |> put_req_header("accept", "application/json")
+        |> delete("/api/pleroma/admin/users", %{
+          nicknames: [user_one.nickname, user_two.nickname]
+        })
+
+      log_entry = Repo.one(ModerationLog)
+
+      assert ModerationLog.get_log_entry_message(log_entry) ==
+               "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
+
+      response = json_response(conn, 200)
+      assert response -- [user_one.nickname, user_two.nickname] == []
+    end
+  end
+
+  describe "/api/pleroma/admin/users" do
     test "Create" do
       admin = insert(:user, info: %{is_admin: true})
 
@@ -404,6 +425,29 @@ test "/:right POST, can add to a permission group" do
                "@#{admin.nickname} made @#{user.nickname} admin"
     end
 
+    test "/:right POST, can add to a permission group (multiple)" do
+      admin = insert(:user, info: %{is_admin: true})
+      user_one = insert(:user)
+      user_two = insert(:user)
+
+      conn =
+        build_conn()
+        |> assign(:user, admin)
+        |> put_req_header("accept", "application/json")
+        |> post("/api/pleroma/admin/users/permission_group/admin", %{
+          nicknames: [user_one.nickname, user_two.nickname]
+        })
+
+      assert json_response(conn, 200) == %{
+               "is_admin" => true
+             }
+
+      log_entry = Repo.one(ModerationLog)
+
+      assert ModerationLog.get_log_entry_message(log_entry) ==
+               "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
+    end
+
     test "/:right DELETE, can remove from a permission group" do
       admin = insert(:user, info: %{is_admin: true})
       user = insert(:user, info: %{is_admin: true})
@@ -423,63 +467,30 @@ test "/:right DELETE, can remove from a permission group" do
       assert ModerationLog.get_log_entry_message(log_entry) ==
                "@#{admin.nickname} revoked admin role from @#{user.nickname}"
     end
-  end
 
-  describe "PUT /api/pleroma/admin/users/:nickname/activation_status" do
-    setup %{conn: conn} do
+    test "/:right DELETE, can remove from a permission group (multiple)" do
       admin = insert(:user, info: %{is_admin: true})
+      user_one = insert(:user, info: %{is_admin: true})
+      user_two = insert(:user, info: %{is_admin: true})
 
       conn =
-        conn
+        build_conn()
         |> assign(:user, admin)
         |> put_req_header("accept", "application/json")
+        |> delete("/api/pleroma/admin/users/permission_group/admin", %{
+          nicknames: [user_one.nickname, user_two.nickname]
+        })
 
-      %{conn: conn, admin: admin}
-    end
-
-    test "deactivates the user", %{conn: conn, admin: admin} do
-      user = insert(:user)
-
-      conn =
-        conn
-        |> put("/api/pleroma/admin/users/#{user.nickname}/activation_status", %{status: false})
-
-      user = User.get_cached_by_id(user.id)
-      assert user.info.deactivated == true
-      assert json_response(conn, :no_content)
+      assert json_response(conn, 200) == %{
+               "is_admin" => false
+             }
 
       log_entry = Repo.one(ModerationLog)
 
       assert ModerationLog.get_log_entry_message(log_entry) ==
-               "@#{admin.nickname} deactivated user @#{user.nickname}"
-    end
-
-    test "activates the user", %{conn: conn, admin: admin} do
-      user = insert(:user, info: %{deactivated: true})
-
-      conn =
-        conn
-        |> put("/api/pleroma/admin/users/#{user.nickname}/activation_status", %{status: true})
-
-      user = User.get_cached_by_id(user.id)
-      assert user.info.deactivated == false
-      assert json_response(conn, :no_content)
-
-      log_entry = Repo.one(ModerationLog)
-
-      assert ModerationLog.get_log_entry_message(log_entry) ==
-               "@#{admin.nickname} activated user @#{user.nickname}"
-    end
-
-    test "returns 403 when requested by a non-admin", %{conn: conn} do
-      user = insert(:user)
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> put("/api/pleroma/admin/users/#{user.nickname}/activation_status", %{status: false})
-
-      assert json_response(conn, :forbidden)
+               "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
+                 user_two.nickname
+               }"
     end
   end
 
@@ -1029,6 +1040,50 @@ test "it works with multiple filters" do
     end
   end
 
+  test "PATCH /api/pleroma/admin/users/activate" do
+    admin = insert(:user, info: %{is_admin: true})
+    user_one = insert(:user, info: %{deactivated: true})
+    user_two = insert(:user, info: %{deactivated: true})
+
+    conn =
+      build_conn()
+      |> assign(:user, admin)
+      |> patch(
+        "/api/pleroma/admin/users/activate",
+        %{nicknames: [user_one.nickname, user_two.nickname]}
+      )
+
+    response = json_response(conn, 200)
+    assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
+
+    log_entry = Repo.one(ModerationLog)
+
+    assert ModerationLog.get_log_entry_message(log_entry) ==
+             "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
+  end
+
+  test "PATCH /api/pleroma/admin/users/deactivate" do
+    admin = insert(:user, info: %{is_admin: true})
+    user_one = insert(:user, info: %{deactivated: false})
+    user_two = insert(:user, info: %{deactivated: false})
+
+    conn =
+      build_conn()
+      |> assign(:user, admin)
+      |> patch(
+        "/api/pleroma/admin/users/deactivate",
+        %{nicknames: [user_one.nickname, user_two.nickname]}
+      )
+
+    response = json_response(conn, 200)
+    assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
+
+    log_entry = Repo.one(ModerationLog)
+
+    assert ModerationLog.get_log_entry_message(log_entry) ==
+             "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
+  end
+
   test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do
     admin = insert(:user, info: %{is_admin: true})
     user = insert(:user)
@@ -1053,7 +1108,7 @@ test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do
     log_entry = Repo.one(ModerationLog)
 
     assert ModerationLog.get_log_entry_message(log_entry) ==
-             "@#{admin.nickname} deactivated user @#{user.nickname}"
+             "@#{admin.nickname} deactivated users: @#{user.nickname}"
   end
 
   describe "POST /api/pleroma/admin/users/invite_token" do