diff --git a/locales/en-US.yml b/locales/en-US.yml
index 4ae4094773..234ab73a69 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -1065,6 +1065,7 @@ update: "Update"
 rolesThatCanBeUsedThisEmojiAsReaction: "Roles that can use this emoji as reaction"
 rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "If no roles are specified, anyone can use this emoji as reaction."
 rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "These roles must be public."
+rolesThatCanNotBeUsedThisEmojiAsReaction: "Roles that can not use this emoji as reaction"
 cancelReactionConfirm: "Really delete your reaction?"
 changeReactionConfirm: "Really change your reaction?"
 later: "Later"
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 7fc21a1ccc..e97eec6c6d 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -1068,6 +1068,7 @@ export interface Locale {
     "rolesThatCanBeUsedThisEmojiAsReaction": string;
     "rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription": string;
     "rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn": string;
+    "rolesThatCanNotBeUsedThisEmojiAsReaction": string;
     "cancelReactionConfirm": string;
     "changeReactionConfirm": string;
     "later": string;
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index d5c50b59d2..a4d877954e 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1065,6 +1065,7 @@ update: "更新"
 rolesThatCanBeUsedThisEmojiAsReaction: "リアクションとして使えるロール"
 rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ロールの指定が一つもない場合、誰でもリアクションとして使えます。"
 rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "ロールは公開ロールである必要があります。"
+rolesThatCanNotBeUsedThisEmojiAsReaction: "リアクションとして使えないロール"
 cancelReactionConfirm: "リアクションを取り消しますか?"
 changeReactionConfirm: "リアクションを変更しますか?"
 later: "あとで"
diff --git a/packages/backend/migration/1691317808362-customemoji-restricted-roles.js b/packages/backend/migration/1691317808362-customemoji-restricted-roles.js
new file mode 100644
index 0000000000..84e88229c2
--- /dev/null
+++ b/packages/backend/migration/1691317808362-customemoji-restricted-roles.js
@@ -0,0 +1,11 @@
+export class CustomemojiRestrictedRoles1691317808362 {
+    name = 'CustomemojiRestrictedRoles1691317808362'
+
+    async up(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "emoji" ADD "roleIdsThatCanNotBeUsedThisEmojiAsReaction" character varying(128) array NOT NULL DEFAULT '{}'`);
+    }
+
+    async down(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "emoji" DROP COLUMN "roleIdsThatCanNotBeUsedThisEmojiAsReaction"`);
+    }
+}
diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts
index 661d956bd6..5a8721d66d 100644
--- a/packages/backend/src/core/CustomEmojiService.ts
+++ b/packages/backend/src/core/CustomEmojiService.ts
@@ -68,6 +68,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
 		isSensitive: boolean;
 		localOnly: boolean;
 		roleIdsThatCanBeUsedThisEmojiAsReaction: Role['id'][];
+		roleIdsThatCanNotBeUsedThisEmojiAsReaction: Role['id'][];
 	}): Promise<Emoji> {
 		const emoji = await this.emojisRepository.insert({
 			id: this.idService.genId(),
@@ -83,6 +84,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
 			isSensitive: data.isSensitive,
 			localOnly: data.localOnly,
 			roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction,
+			roleIdsThatCanNotBeUsedThisEmojiAsReaction: data.roleIdsThatCanNotBeUsedThisEmojiAsReaction,
 		}).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0]));
 
 		if (data.host == null) {
@@ -106,6 +108,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
 		isSensitive?: boolean;
 		localOnly?: boolean;
 		roleIdsThatCanBeUsedThisEmojiAsReaction?: Role['id'][];
+		roleIdsThatCanNotBeUsedThisEmojiAsReaction?: Role['id'][];
 	}): Promise<void> {
 		const emoji = await this.emojisRepository.findOneByOrFail({ id: id });
 		const sameNameEmoji = await this.emojisRepository.findOneBy({ name: data.name, host: IsNull() });
@@ -123,6 +126,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
 			publicUrl: data.driveFile != null ? (data.driveFile.webpublicUrl ?? data.driveFile.url) : undefined,
 			type: data.driveFile != null ? (data.driveFile.webpublicType ?? data.driveFile.type) : undefined,
 			roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction ?? undefined,
+			roleIdsThatCanNotBeUsedThisEmojiAsReaction: data.roleIdsThatCanNotBeUsedThisEmojiAsReaction ?? undefined,
 		});
 
 		this.localEmojisCache.refresh();
diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts
index 4b01b6af7e..be0581a6f4 100644
--- a/packages/backend/src/core/ReactionService.ts
+++ b/packages/backend/src/core/ReactionService.ts
@@ -122,7 +122,10 @@ export class ReactionService {
 					});
 
 				if (emoji) {
-					if (emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0 || (await this.roleService.getUserRoles(user.id)).some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.includes(r.id))) {
+					if (
+						(emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0 || (await this.roleService.getUserRoles(user.id)).some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.includes(r.id))) &&
+						(emoji.roleIdsThatCanNotBeUsedThisEmojiAsReaction.length === 0 || !(await this.roleService.getUserRoles(user.id)).some(r => emoji.roleIdsThatCanNotBeUsedThisEmojiAsReaction.includes(r.id)))
+					) {
 						reaction = reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`;
 
 						// センシティブ
diff --git a/packages/backend/src/core/entities/EmojiEntityService.ts b/packages/backend/src/core/entities/EmojiEntityService.ts
index 4a18cd1b3b..74740c70de 100644
--- a/packages/backend/src/core/entities/EmojiEntityService.ts
+++ b/packages/backend/src/core/entities/EmojiEntityService.ts
@@ -28,6 +28,7 @@ export class EmojiEntityService {
 			url: emoji.publicUrl || emoji.originalUrl,
 			isSensitive: emoji.isSensitive ? true : undefined,
 			roleIdsThatCanBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length > 0 ? emoji.roleIdsThatCanBeUsedThisEmojiAsReaction : undefined,
+			roleIdsThatCanNotBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanNotBeUsedThisEmojiAsReaction.length > 0 ? emoji.roleIdsThatCanNotBeUsedThisEmojiAsReaction : undefined,
 		};
 	}
 
@@ -56,6 +57,7 @@ export class EmojiEntityService {
 			isSensitive: emoji.isSensitive,
 			localOnly: emoji.localOnly,
 			roleIdsThatCanBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanBeUsedThisEmojiAsReaction,
+			roleIdsThatCanNotBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanNotBeUsedThisEmojiAsReaction,
 		};
 	}
 
diff --git a/packages/backend/src/models/entities/Emoji.ts b/packages/backend/src/models/entities/Emoji.ts
index 8fd3e65f5e..98c1732fd5 100644
--- a/packages/backend/src/models/entities/Emoji.ts
+++ b/packages/backend/src/models/entities/Emoji.ts
@@ -76,4 +76,9 @@ export class Emoji {
 		array: true, length: 128, default: '{}',
 	})
 	public roleIdsThatCanBeUsedThisEmojiAsReaction: string[];
+
+	@Column('varchar', {
+		array: true, length: 128, default: '{}',
+	})
+	public roleIdsThatCanNotBeUsedThisEmojiAsReaction: string[];
 }
diff --git a/packages/backend/src/models/json-schema/emoji.ts b/packages/backend/src/models/json-schema/emoji.ts
index 63f56e77cb..85cd5900ac 100644
--- a/packages/backend/src/models/json-schema/emoji.ts
+++ b/packages/backend/src/models/json-schema/emoji.ts
@@ -35,6 +35,15 @@ export const packedEmojiSimpleSchema = {
 				format: 'id',
 			},
 		},
+		roleIdsThatCanNotBeUsedThisEmojiAsReaction: {
+			type: 'array',
+			optional: true, nullable: false,
+			items: {
+				type: 'string',
+				optional: false, nullable: false,
+				format: 'id',
+			},
+		},
 	},
 } as const;
 
@@ -86,7 +95,16 @@ export const packedEmojiDetailedSchema = {
 		},
 		roleIdsThatCanBeUsedThisEmojiAsReaction: {
 			type: 'array',
-			optional: false, nullable: false,
+			optional: true, nullable: false,
+			items: {
+				type: 'string',
+				optional: false, nullable: false,
+				format: 'id',
+			},
+		},
+		roleIdsThatCanNotBeUsedThisEmojiAsReaction: {
+			type: 'array',
+			optional: true, nullable: false,
 			items: {
 				type: 'string',
 				optional: false, nullable: false,
diff --git a/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts b/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts
index 37b929cb03..651858178d 100644
--- a/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts
+++ b/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts
@@ -109,6 +109,7 @@ export class ImportCustomEmojisProcessorService {
 					isSensitive: emojiInfo.isSensitive,
 					localOnly: emojiInfo.localOnly,
 					roleIdsThatCanBeUsedThisEmojiAsReaction: [],
+					roleIdsThatCanNotBeUsedThisEmojiAsReaction: [],
 				});
 			}
 
diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts
index 200ede0b06..06d4309112 100644
--- a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts
+++ b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts
@@ -40,6 +40,11 @@ export const paramDef = {
 		localOnly: { type: 'boolean' },
 		roleIdsThatCanBeUsedThisEmojiAsReaction: { type: 'array', items: {
 			type: 'string',
+			format: 'misskey:id',
+		} },
+		roleIdsThatCanNotBeUsedThisEmojiAsReaction: { type: 'array', items: {
+			type: 'string',
+			format: 'misskey:id',
 		} },
 	},
 	required: ['name', 'fileId'],
@@ -73,6 +78,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 				isSensitive: ps.isSensitive ?? false,
 				localOnly: ps.localOnly ?? false,
 				roleIdsThatCanBeUsedThisEmojiAsReaction: ps.roleIdsThatCanBeUsedThisEmojiAsReaction ?? [],
+				roleIdsThatCanNotBeUsedThisEmojiAsReaction: ps.roleIdsThatCanNotBeUsedThisEmojiAsReaction ?? [],
 			});
 
 			this.moderationLogService.insertModerationLog(me, 'addEmoji', {
diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts
index edc1af5a53..92ef171a65 100644
--- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts
+++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts
@@ -49,6 +49,11 @@ export const paramDef = {
 		localOnly: { type: 'boolean' },
 		roleIdsThatCanBeUsedThisEmojiAsReaction: { type: 'array', items: {
 			type: 'string',
+			format: 'misskey:id',
+		} },
+		roleIdsThatCanNotBeUsedThisEmojiAsReaction: { type: 'array', items: {
+			type: 'string',
+			format: 'misskey:id',
 		} },
 	},
 	required: ['id', 'name', 'aliases'],
@@ -80,6 +85,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 				isSensitive: ps.isSensitive,
 				localOnly: ps.localOnly,
 				roleIdsThatCanBeUsedThisEmojiAsReaction: ps.roleIdsThatCanBeUsedThisEmojiAsReaction,
+				roleIdsThatCanNotBeUsedThisEmojiAsReaction: ps.roleIdsThatCanNotBeUsedThisEmojiAsReaction,
 			});
 		});
 	}
diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue
index be7e38a343..75904c48de 100644
--- a/packages/frontend/src/components/MkEmojiPicker.vue
+++ b/packages/frontend/src/components/MkEmojiPicker.vue
@@ -284,7 +284,8 @@ watch(q, () => {
 });
 
 function filterAvailable(emoji: Misskey.entities.CustomEmoji): boolean {
-	return (emoji.roleIdsThatCanBeUsedThisEmojiAsReaction == null || emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0) || ($i && $i.roles.some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.includes(r.id)));
+	return ((emoji.roleIdsThatCanBeUsedThisEmojiAsReaction === undefined || emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0) || ($i && $i.roles.some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.includes(r.id)))) &&
+		((emoji.roleIdsThatCanNotBeUsedThisEmojiAsReaction === undefined || emoji.roleIdsThatCanNotBeUsedThisEmojiAsReaction.length === 0) || ($i && !$i.roles.some(r => emoji.roleIdsThatCanNotBeUsedThisEmojiAsReaction.includes(r.id))));
 }
 
 function focus() {
diff --git a/packages/frontend/src/pages/emoji-edit-dialog.vue b/packages/frontend/src/pages/emoji-edit-dialog.vue
index 58f865e033..dd8c871235 100644
--- a/packages/frontend/src/pages/emoji-edit-dialog.vue
+++ b/packages/frontend/src/pages/emoji-edit-dialog.vue
@@ -44,11 +44,28 @@
 					<template #suffix>{{ rolesThatCanBeUsedThisEmojiAsReaction.length === 0 ? i18n.ts.all : rolesThatCanBeUsedThisEmojiAsReaction.length }}</template>
 
 					<div class="_gaps">
-						<MkButton rounded @click="addRole"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
+						<MkButton rounded @click="addRole(true)"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
 
 						<div v-for="role in rolesThatCanBeUsedThisEmojiAsReaction" :key="role.id" :class="$style.roleItem">
 							<MkRolePreview :class="$style.role" :role="role" :forModeration="true" :detailed="false" style="pointer-events: none;"/>
-							<button v-if="role.target === 'manual'" class="_button" :class="$style.roleUnassign" @click="removeRole(role, $event)"><i class="ti ti-x"></i></button>
+							<button v-if="role.target === 'manual'" class="_button" :class="$style.roleUnassign" @click="removeRole(true, role, $event)"><i class="ti ti-x"></i></button>
+							<button v-else class="_button" :class="$style.roleUnassign" disabled><i class="ti ti-ban"></i></button>
+						</div>
+
+						<MkInfo>{{ i18n.ts.rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription }}</MkInfo>
+						<MkInfo warn>{{ i18n.ts.rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn }}</MkInfo>
+					</div>
+				</MkFolder>
+				<MkFolder>
+					<template #label>{{ i18n.ts.rolesThatCanNotBeUsedThisEmojiAsReaction }}</template>
+					<template #suffix>{{ rolesThatCanNotBeUsedThisEmojiAsReaction.length === 0 ? i18n.ts.none : rolesThatCanNotBeUsedThisEmojiAsReaction.length }}</template>
+
+					<div class="_gaps">
+						<MkButton rounded @click="addRole(false)"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
+
+						<div v-for="role in rolesThatCanNotBeUsedThisEmojiAsReaction" :key="role.id" :class="$style.roleItem">
+							<MkRolePreview :class="$style.role" :role="role" :forModeration="true" :detailed="false" style="pointer-events: none;"/>
+							<button v-if="role.target === 'manual'" class="_button" :class="$style.roleUnassign" @click="removeRole(false, role, $event)"><i class="ti ti-x"></i></button>
 							<button v-else class="_button" :class="$style.roleUnassign" disabled><i class="ti ti-ban"></i></button>
 						</div>
 
@@ -97,12 +114,18 @@ let isSensitive = $ref(props.emoji ? props.emoji.isSensitive : false);
 let localOnly = $ref(props.emoji ? props.emoji.localOnly : false);
 let roleIdsThatCanBeUsedThisEmojiAsReaction = $ref(props.emoji ? props.emoji.roleIdsThatCanBeUsedThisEmojiAsReaction : []);
 let rolesThatCanBeUsedThisEmojiAsReaction = $ref([]);
+let roleIdsThatCanNotBeUsedThisEmojiAsReaction = $ref(props.emoji ? props.emoji.roleIdsThatCanNotBeUsedThisEmojiAsReaction : []);
+let rolesThatCanNotBeUsedThisEmojiAsReaction = $ref([]);
 let file = $ref<misskey.entities.DriveFile>();
 
 watch($$(roleIdsThatCanBeUsedThisEmojiAsReaction), async () => {
 	rolesThatCanBeUsedThisEmojiAsReaction = (await Promise.all(roleIdsThatCanBeUsedThisEmojiAsReaction.map((id) => os.api('admin/roles/show', { roleId: id }).catch(() => null)))).filter(x => x != null);
 }, { immediate: true });
 
+watch($$(roleIdsThatCanNotBeUsedThisEmojiAsReaction), async () => {
+	rolesThatCanNotBeUsedThisEmojiAsReaction = (await Promise.all(roleIdsThatCanNotBeUsedThisEmojiAsReaction.map((id) => os.api('admin/roles/show', { roleId: id }).catch(() => null)))).filter(x => x != null);
+}, { immediate: true });
+
 const imgUrl = computed(() => file ? file.url : props.emoji ? `/emoji/${props.emoji.name}.webp` : null);
 
 const emit = defineEmits<{
@@ -118,20 +141,22 @@ async function changeImage(ev) {
 	}
 }
 
-async function addRole() {
+async function addRole(type: boolean) {
 	const roles = await os.api('admin/roles/list');
-	const currentRoleIds = rolesThatCanBeUsedThisEmojiAsReaction.map(x => x.id);
+	const currentRoleIds = type ? rolesThatCanBeUsedThisEmojiAsReaction.map(x => x.id) : rolesThatCanNotBeUsedThisEmojiAsReaction.map(x => x.id);
 
 	const { canceled, result: role } = await os.select({
 		items: roles.filter(r => r.isPublic).filter(r => !currentRoleIds.includes(r.id)).map(r => ({ text: r.name, value: r })),
 	});
 	if (canceled) return;
 
-	rolesThatCanBeUsedThisEmojiAsReaction.push(role);
+	if (type) rolesThatCanBeUsedThisEmojiAsReaction.push(role);
+	else rolesThatCanNotBeUsedThisEmojiAsReaction.push(role);
 }
 
-async function removeRole(role, ev) {
-	rolesThatCanBeUsedThisEmojiAsReaction = rolesThatCanBeUsedThisEmojiAsReaction.filter(x => x.id !== role.id);
+async function removeRole(type: boolean, role, ev) {
+	if (type) rolesThatCanBeUsedThisEmojiAsReaction = rolesThatCanBeUsedThisEmojiAsReaction.filter(x => x.id !== role.id);
+	else rolesThatCanNotBeUsedThisEmojiAsReaction = rolesThatCanNotBeUsedThisEmojiAsReaction.filter(x => x.id !== role.id);
 }
 
 async function done() {
@@ -143,6 +168,7 @@ async function done() {
 		isSensitive,
 		localOnly,
 		roleIdsThatCanBeUsedThisEmojiAsReaction: rolesThatCanBeUsedThisEmojiAsReaction.map(x => x.id),
+		roleIdsThatCanNotBeUsedThisEmojiAsReaction: rolesThatCanNotBeUsedThisEmojiAsReaction.map(x => x.id),
 	};
 
 	if (file) {
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 62152384fc..e62cd7451f 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -263,6 +263,9 @@ type CustomEmoji = {
     url: string;
     category: string;
     aliases: string[];
+    isSensitive?: boolean;
+    roleIdsThatCanBeUsedThisEmojiAsReaction?: string[];
+    roleIdsThatCanNotBeUsedThisEmojiAsReaction?: string[];
 };
 
 // @public (undocumented)
diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts
index 9cf0045288..a338fa9ad9 100644
--- a/packages/misskey-js/src/entities.ts
+++ b/packages/misskey-js/src/entities.ts
@@ -281,6 +281,9 @@ export type CustomEmoji = {
 	url: string;
 	category: string;
 	aliases: string[];
+	isSensitive?: boolean;
+	roleIdsThatCanBeUsedThisEmojiAsReaction?: string[];
+	roleIdsThatCanNotBeUsedThisEmojiAsReaction?: string[];
 };
 
 export type LiteInstanceMetadata = {