diff --git a/app/lib/admin/actions/actions.dart b/app/lib/admin/actions/actions.dart
index 5fd6be94f2..58653c560f 100644
--- a/app/lib/admin/actions/actions.dart
+++ b/app/lib/admin/actions/actions.dart
@@ -27,7 +27,6 @@ import 'package_reservation_delete.dart';
 import 'package_reservation_list.dart';
 import 'package_version_info.dart';
 import 'package_version_retraction.dart';
-import 'publisher_block.dart';
 import 'publisher_create.dart';
 import 'publisher_delete.dart';
 import 'publisher_info.dart';
@@ -114,7 +113,6 @@ final class AdminAction {
     packageReservationList,
     packageVersionInfo,
     packageVersionRetraction,
-    publisherBlock,
     publisherCreate,
     publisherDelete,
     publisherInfo,
diff --git a/app/lib/admin/actions/publisher_block.dart b/app/lib/admin/actions/publisher_block.dart
deleted file mode 100644
index aeef7b8946..0000000000
--- a/app/lib/admin/actions/publisher_block.dart
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:pub_dev/account/backend.dart';
-import 'package:pub_dev/admin/actions/actions.dart';
-import 'package:pub_dev/publisher/backend.dart';
-import 'package:pub_dev/publisher/models.dart';
-import 'package:pub_dev/shared/datastore.dart';
-
-final publisherBlock = AdminAction(
-  name: 'publisher-block',
-  summary: 'Block publisher and block all members',
-  description: '''
-Get information about publisher and list all members.
-''',
-  options: {
-    'publisher': 'Publisher to be blocked',
-  },
-  invoke: (options) async {
-    final publisherId = options['publisher'] ??
-        (throw InvalidInputException('Missing --publisher argument.'));
-    InvalidInputException.check(
-      publisherId.isNotEmpty,
-      'publisher must be given',
-    );
-
-    final publisher = await publisherBackend.getPublisher(publisherId);
-    if (publisher == null) {
-      throw NotFoundException.resource(publisherId);
-    }
-    final members = await publisherBackend.listPublisherMembers(publisherId);
-
-    for (final m in members) {
-      await accountBackend.updateBlockedFlag(m.userId, true);
-    }
-
-    final publisherKey = dbService.emptyKey.append(Publisher, id: publisherId);
-    await withRetryTransaction(dbService, (tx) async {
-      final p = await tx.lookupValue<Publisher>(publisherKey);
-      p.markForBlocked();
-      tx.insert(p);
-    });
-
-    return {
-      'publisher': publisher.publisherId,
-      'description': publisher.description,
-      'website': publisher.websiteUrl,
-      'contact': publisher.contactEmail,
-      'created': publisher.created,
-      'blocked': true,
-      'members': members
-          .map((m) => {
-                'email': m.email,
-                'role': m.role,
-                'userId': m.userId,
-                'blocked': true,
-              })
-          .toList(),
-    };
-  },
-);
diff --git a/app/lib/admin/backend.dart b/app/lib/admin/backend.dart
index 058769157e..38c4e69eb1 100644
--- a/app/lib/admin/backend.dart
+++ b/app/lib/admin/backend.dart
@@ -35,14 +35,11 @@ import '../shared/versions.dart';
 import '../task/backend.dart';
 import 'actions/actions.dart' show AdminAction;
 import 'tools/delete_all_staging.dart';
-import 'tools/list_package_blocked.dart';
 import 'tools/list_tools.dart';
 import 'tools/notify_service.dart';
 import 'tools/package_publisher.dart';
 import 'tools/publisher_member.dart';
 import 'tools/recent_uploaders.dart';
-import 'tools/set_package_blocked.dart';
-import 'tools/set_user_blocked.dart';
 import 'tools/user_merger.dart';
 
 final _logger = Logger('pub.admin.backend');
@@ -59,14 +56,11 @@ typedef Tool = Future<String> Function(List<String> args);
 
 final Map<String, Tool> availableTools = {
   'delete-all-staging': executeDeleteAllStaging,
-  'list-package-blocked': executeListPackageBlocked,
   'notify-service': executeNotifyService,
   'package-publisher': executeSetPackagePublisher,
   'recent-uploaders': executeRecentUploaders,
   'publisher-member': executePublisherMember,
   'publisher-invite-member': executePublisherInviteMember,
-  'set-package-blocked': executeSetPackageBlocked,
-  'set-user-blocked': executeSetUserBlocked,
   'user-merger': executeUserMergerTool,
   'list-tools': executeListTools,
 };
diff --git a/app/lib/admin/tools/list_package_blocked.dart b/app/lib/admin/tools/list_package_blocked.dart
deleted file mode 100644
index d86cf4c21e..0000000000
--- a/app/lib/admin/tools/list_package_blocked.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:args/args.dart';
-
-import '../../package/models.dart';
-import '../../shared/datastore.dart';
-
-final _argParser = ArgParser()
-  ..addFlag('help', abbr: 'h', defaultsTo: false, help: 'Show help.');
-
-Future<String> executeListPackageBlocked(List<String> args) async {
-  final argv = _argParser.parse(args);
-
-  if (argv['help'] as bool) {
-    return 'List packages that are blocked.\n'
-        '${_argParser.usage}';
-  }
-
-  final query = dbService.query<Package>()..filter('isBlocked =', true);
-  final output = StringBuffer();
-  await for (final p in query.run()) {
-    output.writeln(p.name!);
-  }
-  return output.toString();
-}
diff --git a/app/lib/admin/tools/set_package_blocked.dart b/app/lib/admin/tools/set_package_blocked.dart
deleted file mode 100644
index 3eec0e40e1..0000000000
--- a/app/lib/admin/tools/set_package_blocked.dart
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:args/args.dart';
-
-import 'package:pub_dev/account/backend.dart';
-import 'package:pub_dev/package/backend.dart';
-import 'package:pub_dev/package/models.dart';
-import 'package:pub_dev/shared/datastore.dart';
-import 'package:pub_dev/shared/exceptions.dart';
-
-final _argParser = ArgParser()
-  ..addOption('lookup', allowed: ['package', 'publisher', 'userid', 'email'])
-  ..addOption('update', allowed: ['true', 'false'])
-  ..addOption('reason', help: 'The reason of blocked status.')
-  ..addFlag('help', abbr: 'h', defaultsTo: false, help: 'Show help.');
-
-Future<String> executeSetPackageBlocked(List<String> args) async {
-  final argv = _argParser.parse(args);
-  final blockedStatus = _parseValue(argv['update'] as String?);
-  final blockedReason = argv['reason'] as String?;
-  final lookupKey = argv['lookup'] as String?;
-
-  if (argv['help'] as bool || lookupKey == null) {
-    return 'Usage: <tool> --lookup package [pkg1] [pkg2] -- list status of packages\n'
-        'Usage: <tool> --lookup publisher [publisher1] [publisher2] -- list status of packages from publishers\n'
-        'Usage: <tool> --lookup userid [user1] [user2] -- list status of packages from uploaders\n'
-        'Usage: <tool> --lookup email [email1] [email2] -- list status of packages from uploaders\n'
-        'Usage: <tool> --update true --lookup email [email1] [email2] -- update status of packages from uploaders\n'
-        '${_argParser.usage}';
-  }
-
-  final packages = <String, Package>{};
-
-  Future<void> loadPackages(String name, String? value) async {
-    final query = dbService.query<Package>()..filter('$name =', value);
-    await for (final p in query.run()) {
-      packages[p.name!] = p;
-    }
-  }
-
-  InvalidInputException.checkAnyOf(
-      lookupKey, 'lookupKey', ['package', 'publisher', 'userid', 'email']);
-  if (lookupKey == 'package') {
-    for (final name in argv.rest) {
-      final p = (await packageBackend.lookupPackage(name))!;
-      packages[p.name!] = p;
-    }
-  } else if (lookupKey == 'publisher') {
-    for (final publisherId in argv.rest) {
-      await loadPackages('publisherId', publisherId);
-    }
-  } else if (lookupKey == 'userid') {
-    for (final userId in argv.rest) {
-      await loadPackages('uploaders', userId);
-    }
-  } else if (lookupKey == 'email') {
-    for (final email in argv.rest) {
-      final users = await accountBackend.lookupUsersByEmail(email);
-      InvalidInputException.check(
-          users.isNotEmpty, 'Email lookup failed: $email');
-      for (final u in users) {
-        await loadPackages('uploaders', u.userId);
-      }
-    }
-  }
-
-  final output = StringBuffer();
-  output.writeln('Found ${packages.length} packages.');
-  final orderedNames = packages.keys.toList()..sort();
-  for (final name in orderedNames) {
-    final p = packages[name]!;
-    output.writeln('${p.name!.padRight(40)} - ${p.isBlocked}');
-  }
-
-  if (blockedStatus != null) {
-    for (final name in orderedNames) {
-      final p = packages[name]!;
-      final out = await _updateStatus(p, blockedStatus, blockedReason);
-      if (out.isNotEmpty) {
-        output.writeln(out);
-      }
-    }
-  }
-  return output.toString();
-}
-
-Future<String> _updateStatus(Package pkg, bool status, String? reason) async {
-  if (pkg.isBlocked == status) {
-    return '';
-  }
-  await withRetryTransaction(dbService, (tx) async {
-    final p = await tx.lookupValue<Package>(pkg.key);
-    p.updateIsBlocked(isBlocked: status, reason: reason);
-    tx.insert(p);
-  });
-  await purgePackageCache(pkg.name!);
-  return ('Updating ${pkg.name!.padRight(40)} - ${pkg.isBlocked} -> $status');
-}
-
-bool? _parseValue(String? value) {
-  if (value == null) return null;
-  if (value == 'true') return true;
-  if (value == 'false') return false;
-  throw ArgumentError('Unknown bool value: $value');
-}
diff --git a/app/lib/admin/tools/set_user_blocked.dart b/app/lib/admin/tools/set_user_blocked.dart
deleted file mode 100644
index 10107fb396..0000000000
--- a/app/lib/admin/tools/set_user_blocked.dart
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:pub_dev/account/backend.dart';
-import 'package:pub_dev/account/models.dart';
-import 'package:pub_dev/service/email/email_templates.dart';
-
-Future<String> executeSetUserBlocked(List<String> args) async {
-  if (args.isEmpty || args.length > 2) {
-    return 'Sets the blocked flag on a User.\n'
-        '  <tools-command> <id|email> - get status\n'
-        '  <tools-command> <id|email> <true|false> - set status\n';
-  }
-  final idOrEmail = args[0];
-  final valueAsString = args.length == 2 ? args[1] : null;
-  final blockedStatus = _parseValue(valueAsString);
-
-  final List<User> users;
-  if (isValidEmail(idOrEmail)) {
-    users = await accountBackend.lookupUsersByEmail(idOrEmail);
-  } else {
-    final user = await accountBackend.lookupUserById(idOrEmail);
-    users = user == null ? [] : [user];
-  }
-  if (users.isEmpty) {
-    return 'No user found.';
-  }
-  final output = StringBuffer();
-  for (final user in users) {
-    if (blockedStatus == null) {
-      output.write('userId: ${user.userId}\n'
-          'email: ${user.email}\n'
-          'isBlocked: ${user.isBlocked}\n');
-    } else {
-      await accountBackend.updateBlockedFlag(user.userId, blockedStatus);
-      output.writeln('Updated: ${user.userId} -> $blockedStatus');
-    }
-  }
-  return output.toString();
-}
-
-bool? _parseValue(String? value) {
-  if (value == null) return null;
-  if (value == 'true') return true;
-  if (value == 'false') return false;
-  throw ArgumentError('Unknown bool value: $value');
-}
diff --git a/app/lib/package/models.dart b/app/lib/package/models.dart
index 47d65c2c63..bffe4783c0 100644
--- a/app/lib/package/models.dart
+++ b/app/lib/package/models.dart
@@ -413,16 +413,6 @@ class Package extends db.ExpandoModel<String> {
     );
   }
 
-  void updateIsBlocked({
-    required bool isBlocked,
-    String? reason,
-  }) {
-    this.isBlocked = isBlocked;
-    blockedReason = reason;
-    blocked = isBlocked ? clock.now().toUtc() : null;
-    updated = clock.now().toUtc();
-  }
-
   void updateIsModerated({
     required bool isModerated,
   }) {
diff --git a/app/lib/publisher/models.dart b/app/lib/publisher/models.dart
index 5a7895f7e1..79a0929d6f 100644
--- a/app/lib/publisher/models.dart
+++ b/app/lib/publisher/models.dart
@@ -91,15 +91,6 @@ class Publisher extends db.ExpandoModel<String> {
     isModerated = false;
   }
 
-  /// Clears most properties on the entity and sets the [isBlocked] flag.
-  void markForBlocked() {
-    isBlocked = true;
-    isAbandoned = true;
-    contactEmail = null;
-    description = '';
-    updated = clock.now().toUtc();
-  }
-
   /// Whether the publisher has a displayable description.
   bool get hasDescription => description != null && description!.isNotEmpty;
 
diff --git a/app/test/admin/api_test.dart b/app/test/admin/api_test.dart
index a07ae9f659..8e56d3cbc4 100644
--- a/app/test/admin/api_test.dart
+++ b/app/test/admin/api_test.dart
@@ -712,26 +712,6 @@ void main() {
         expect(rs3.isRetracted, v4.isRetracted);
       });
     });
-
-    group('block user', () {
-      setupTestsWithAdminTokenIssues(
-        (client) => client.adminExecuteTool(
-          'set-user-blocked',
-          'user@pub.dev/true',
-        ),
-      );
-
-      testWithProfile('block and unblock user', fn: () async {
-        final client = createPubApiClient(authToken: siteAdminToken);
-        await client.adminExecuteTool('set-user-blocked', 'user@pub.dev/true');
-        final user = await accountBackend.lookupUserByEmail('user@pub.dev');
-        expect(user.isBlocked, true);
-        await client.adminExecuteTool(
-            'set-user-blocked', '${user.userId}/false');
-        final user2 = await accountBackend.lookupUserByEmail('user@pub.dev');
-        expect(user2.isBlocked, false);
-      });
-    });
   });
 }
 
diff --git a/app/test/frontend/handlers/custom_api_test.dart b/app/test/frontend/handlers/custom_api_test.dart
index 8b197bf1e1..20597377e7 100644
--- a/app/test/frontend/handlers/custom_api_test.dart
+++ b/app/test/frontend/handlers/custom_api_test.dart
@@ -147,7 +147,7 @@ void main() {
         },
       );
       final p = await packageBackend.lookupPackage('neon');
-      p!.updateIsBlocked(isBlocked: true, reason: 'spam');
+      p!.updateIsModerated(isModerated: true);
       expect(p.isVisible, isFalse);
       await dbService.commit(inserts: [p]);
       await nameTracker.reloadFromDatastore();
@@ -163,7 +163,7 @@ void main() {
       );
 
       // reverting to make sure integrity check is passing
-      p.updateIsBlocked(isBlocked: false);
+      p.updateIsModerated(isModerated: false);
       await dbService.commit(inserts: [p]);
     });
   });
diff --git a/app/test/frontend/handlers/documentation_test.dart b/app/test/frontend/handlers/documentation_test.dart
index 259991f442..438bb2abf0 100644
--- a/app/test/frontend/handlers/documentation_test.dart
+++ b/app/test/frontend/handlers/documentation_test.dart
@@ -2,9 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:gcloud/db.dart';
 import 'package:pub_dev/frontend/handlers/documentation.dart';
-import 'package:pub_dev/package/backend.dart';
 import 'package:pub_dev/shared/urls.dart';
 import 'package:test/test.dart';
 
@@ -143,15 +141,5 @@ void main() {
       },
       processJobsWithFakeRunners: true,
     );
-
-    testWithProfile('withheld package gets rejected', fn: () async {
-      final pkg = await packageBackend.lookupPackage('oxygen');
-      await dbService.commit(inserts: [pkg!..updateIsBlocked(isBlocked: true)]);
-      await expectNotFoundResponse(
-          await issueGet('/documentation/oxygen/latest/'));
-
-      // reverting to make sure integrity check is passing
-      await dbService.commit(inserts: [pkg..updateIsBlocked(isBlocked: false)]);
-    });
   });
 }
diff --git a/app/test/frontend/handlers/package_test.dart b/app/test/frontend/handlers/package_test.dart
index 1f0d507ad9..773ebe58fd 100644
--- a/app/test/frontend/handlers/package_test.dart
+++ b/app/test/frontend/handlers/package_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:gcloud/db.dart';
-import 'package:pub_dev/package/models.dart';
 import 'package:pub_dev/tool/test_profile/models.dart';
 import 'package:test/test.dart';
 
@@ -43,22 +41,6 @@ void main() {
           '/packages/oxygen/versions/1.2.0/changelog');
     });
 
-    testWithProfile('withheld package - not found', fn: () async {
-      final pkg = await dbService.lookupValue<Package>(
-          dbService.emptyKey.append(Package, id: 'oxygen'));
-      await dbService.commit(inserts: [pkg..updateIsBlocked(isBlocked: true)]);
-      await expectNotFoundResponse(await issueGet('/packages/oxygen'));
-      await expectNotFoundResponse(await issueGet('/packages/oxygen/score'));
-      await expectNotFoundResponse(await issueGet('/packages/oxygen/versions'));
-      await expectNotFoundResponse(
-          await issueGet('/packages/oxygen/versions/${pkg.latestVersion}'));
-      await expectNotFoundResponse(await issueGet(
-          '/packages/oxygen/versions/${pkg.latestVersion}/score'));
-
-      // reverting to make sure integrity check is passing
-      await dbService.commit(inserts: [pkg..updateIsBlocked(isBlocked: false)]);
-    });
-
     testWithProfile('/packages/foobar_not_found - not found', fn: () async {
       await expectNotFoundResponse(
           await issueGet('/packages/foobar_not_found'));
diff --git a/app/test/package/backend_test.dart b/app/test/package/backend_test.dart
index 12d5a76986..29153fee58 100644
--- a/app/test/package/backend_test.dart
+++ b/app/test/package/backend_test.dart
@@ -165,19 +165,6 @@ void main() {
         });
       });
 
-      testWithProfile('blocked user', fn: () async {
-        final user = await accountBackend.lookupUserByEmail('admin@pub.dev');
-        await dbService.commit(inserts: [user..isBlocked = true]);
-        final rs = withFakeAuthRequestContext(
-          adminAtPubDevEmail,
-          () async {
-            return packageBackend.inviteUploader(
-                'oxygen', InviteUploaderRequest(email: 'a@b.com'));
-          },
-        );
-        await expectLater(rs, throwsA(isA<AuthenticationException>()));
-      });
-
       testWithProfile('package does not exist', fn: () async {
         await withFakeAuthRequestContext(adminAtPubDevEmail, () async {
           final rs = packageBackend.inviteUploader(
diff --git a/app/test/package/upload_test.dart b/app/test/package/upload_test.dart
index d1f851fd63..608114a243 100644
--- a/app/test/package/upload_test.dart
+++ b/app/test/package/upload_test.dart
@@ -937,17 +937,6 @@ void main() {
         expect(p2!.versionCount, 3);
       });
 
-      testWithProfile('user is blocked', fn: () async {
-        final user = await accountBackend.lookupUserByEmail('user@pub.dev');
-        await dbService.commit(inserts: [user..isBlocked = true]);
-        final tarball = await packageArchiveBytes(
-            pubspecContent: generatePubspecYaml('pkg', '1.2.3'));
-        final rs = createPubApiClient(authToken: userClientToken)
-            .uploadPackageBytes(tarball);
-        await expectApiException(rs,
-            status: 403, code: 'InsufficientPermissions');
-      });
-
       testWithProfile('upload restriction - no uploads', fn: () async {
         (secretBackend as FakeSecretBackend)
             .update(SecretKey.uploadRestriction, 'no-uploads');
diff --git a/app/test/shared/test_services.dart b/app/test/shared/test_services.dart
index 44444561a4..ace8d243b2 100644
--- a/app/test/shared/test_services.dart
+++ b/app/test/shared/test_services.dart
@@ -240,11 +240,15 @@ void setupTestsWithCallerAuthorizationIssues(
     await expectApiException(rs, status: 403, code: 'InsufficientPermissions');
   });
 
-  testWithProfile('Active user is blocked', fn: () async {
+  testWithProfile('Active user is moderated', fn: () async {
     final users = await dbService.query<User>().run().toList();
     final user = users.firstWhere((u) => u.email == 'admin@pub.dev');
     final client = await createFakeAuthPubApiClient(email: adminAtPubDevEmail);
-    await dbService.commit(inserts: [user..isBlocked = true]);
+    await dbService.commit(inserts: [
+      user
+        ..isModerated = true
+        ..moderatedAt = clock.now()
+    ]);
     final rs = fn(client);
     await expectApiException(rs,
         status: 401, code: 'MissingAuthentication', message: 'failed');
diff --git a/app/test/tool/maintenance/migrate_isblocked_test.dart b/app/test/tool/maintenance/migrate_isblocked_test.dart
index 3d59e13329..7b0c3f7ba6 100644
--- a/app/test/tool/maintenance/migrate_isblocked_test.dart
+++ b/app/test/tool/maintenance/migrate_isblocked_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:clock/clock.dart';
 import 'package:pub_dev/account/backend.dart';
 import 'package:pub_dev/package/backend.dart';
 import 'package:pub_dev/publisher/backend.dart';
@@ -15,8 +16,12 @@ void main() {
   group('Migrate isBlocked', () {
     testWithProfile('package', fn: () async {
       final p1 = await packageBackend.lookupPackage('oxygen');
-      await dbService.commit(
-          inserts: [p1!..updateIsBlocked(isBlocked: true, reason: 'abc')]);
+      await dbService.commit(inserts: [
+        p1!
+          ..isBlocked = true
+          ..blocked = clock.now()
+          ..blockedReason = 'abc'
+      ]);
       await migrateIsBlocked();
 
       final p2 = await packageBackend.lookupPackage('oxygen');
@@ -25,7 +30,7 @@ void main() {
 
     testWithProfile('publisher', fn: () async {
       final p1 = await publisherBackend.getPublisher('example.com');
-      await dbService.commit(inserts: [p1!..markForBlocked()]);
+      await dbService.commit(inserts: [p1!..isBlocked = true]);
       final members =
           await publisherBackend.listPublisherMembers('example.com');
       for (final m in members) {