diff --git a/locales/index.d.ts b/locales/index.d.ts
index f7d875d2c8..6adc66d3cd 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -10529,6 +10529,10 @@ export interface Locale extends ILocale {
          * ギャラリーの投稿を削除
          */
         "deleteGalleryPost": string;
+        /**
+         * チャットルームを削除
+         */
+        "deleteChatRoom": string;
         /**
          * プロキシアカウントの説明を更新
          */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index efaa279454..55bb4c577b 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2791,6 +2791,7 @@ _moderationLogTypes:
   deletePage: "ページを削除"
   deleteFlash: "Playを削除"
   deleteGalleryPost: "ギャラリーの投稿を削除"
+  deleteChatRoom: "チャットルームを削除"
   updateProxyAccountDescription: "プロキシアカウントの説明を更新"
 
 _fileViewer:
diff --git a/packages/backend/src/core/ChatService.ts b/packages/backend/src/core/ChatService.ts
index 4c010b2ef7..35819a4bc2 100644
--- a/packages/backend/src/core/ChatService.ts
+++ b/packages/backend/src/core/ChatService.ts
@@ -27,6 +27,7 @@ import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
 import { CustomEmojiService } from '@/core/CustomEmojiService.js';
 import { emojiRegex } from '@/misc/emoji-regex.js';
 import { NotificationService } from '@/core/NotificationService.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
 
 const MAX_ROOM_MEMBERS = 30;
 const MAX_REACTIONS_PER_MESSAGE = 100;
@@ -75,6 +76,7 @@ export class ChatService {
 		private roleService: RoleService,
 		private userFollowingService: UserFollowingService,
 		private customEmojiService: CustomEmojiService,
+		private moderationLogService: ModerationLogService,
 	) {
 	}
 
@@ -285,6 +287,20 @@ export class ChatService {
 		return this.chatMessagesRepository.findOneBy({ id: messageId, fromUserId: userId });
 	}
 
+	@bindThis
+	public async hasPermissionToViewRoomTimeline(meId: MiUser['id'], room: MiChatRoom) {
+		if (await this.isRoomMember(room, meId)) {
+			return true;
+		} else {
+			const iAmModerator = await this.roleService.isModerator({ id: meId });
+			if (iAmModerator) {
+				return true;
+			}
+
+			return false;
+		}
+	}
+
 	@bindThis
 	public async deleteMessage(message: MiChatMessage) {
 		await this.chatMessagesRepository.delete(message.id);
@@ -493,8 +509,29 @@ export class ChatService {
 	}
 
 	@bindThis
-	public async deleteRoom(room: MiChatRoom) {
+	public async hasPermissionToDeleteRoom(meId: MiUser['id'], room: MiChatRoom) {
+		if (room.ownerId === meId) {
+			return true;
+		}
+
+		const iAmModerator = await this.roleService.isModerator({ id: meId });
+		if (iAmModerator) {
+			return true;
+		}
+
+		return false;
+	}
+
+	@bindThis
+	public async deleteRoom(room: MiChatRoom, moderator?: MiUser) {
 		await this.chatRoomsRepository.delete(room.id);
+
+		if (moderator) {
+			this.moderationLogService.log(moderator, 'deleteChatRoom', {
+				roomId: room.id,
+				room: room,
+			});
+		}
 	}
 
 	@bindThis
diff --git a/packages/backend/src/server/api/endpoints/chat/messages/room-timeline.ts b/packages/backend/src/server/api/endpoints/chat/messages/room-timeline.ts
index ccc0030403..7aef35db04 100644
--- a/packages/backend/src/server/api/endpoints/chat/messages/room-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/chat/messages/room-timeline.ts
@@ -59,7 +59,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				throw new ApiError(meta.errors.noSuchRoom);
 			}
 
-			if (!(await this.chatService.isRoomMember(room, me.id))) {
+			if (!await this.chatService.hasPermissionToViewRoomTimeline(me.id, room)) {
 				throw new ApiError(meta.errors.noSuchRoom);
 			}
 
diff --git a/packages/backend/src/server/api/endpoints/chat/rooms/delete.ts b/packages/backend/src/server/api/endpoints/chat/rooms/delete.ts
index 2ef0a778f1..1d77a06dd8 100644
--- a/packages/backend/src/server/api/endpoints/chat/rooms/delete.ts
+++ b/packages/backend/src/server/api/endpoints/chat/rooms/delete.ts
@@ -42,11 +42,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 		private chatService: ChatService,
 	) {
 		super(meta, paramDef, async (ps, me) => {
-			const room = await this.chatService.findMyRoomById(me.id, ps.roomId);
+			const room = await this.chatService.findRoomById(ps.roomId);
 			if (room == null) {
 				throw new ApiError(meta.errors.noSuchRoom);
 			}
-			await this.chatService.deleteRoom(room);
+
+			if (!await this.chatService.hasPermissionToDeleteRoom(me.id, room)) {
+				throw new ApiError(meta.errors.noSuchRoom);
+			}
+
+			await this.chatService.deleteRoom(room, me);
 		});
 	}
 }
diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts
index 4e215c93c6..5d5f1e3b71 100644
--- a/packages/backend/src/types.ts
+++ b/packages/backend/src/types.ts
@@ -124,6 +124,7 @@ export const moderationLogTypes = [
 	'deletePage',
 	'deleteFlash',
 	'deleteGalleryPost',
+	'deleteChatRoom',
 	'updateProxyAccountDescription',
 ] as const;
 
@@ -377,6 +378,10 @@ export type ModerationLogPayloads = {
 		postUserUsername: string;
 		post: any;
 	};
+	deleteChatRoom: {
+		roomId: string;
+		room: any;
+	};
 	updateProxyAccountDescription: {
 		before: string | null;
 		after: string | null;
diff --git a/packages/frontend/src/pages/admin/modlog.ModLog.vue b/packages/frontend/src/pages/admin/modlog.ModLog.vue
index 9bbe5f2e42..7ab9417267 100644
--- a/packages/frontend/src/pages/admin/modlog.ModLog.vue
+++ b/packages/frontend/src/pages/admin/modlog.ModLog.vue
@@ -40,6 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 					'deletePage',
 					'deleteFlash',
 					'deleteGalleryPost',
+					'deleteChatRoom',
 				].includes(log.type)
 			}"
 		>{{ i18n.ts._moderationLogTypes[log.type] }}</b>
@@ -80,6 +81,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 		<span v-else-if="log.type === 'deletePage'">: @{{ log.info.pageUserUsername }}</span>
 		<span v-else-if="log.type === 'deleteFlash'">: @{{ log.info.flashUserUsername }}</span>
 		<span v-else-if="log.type === 'deleteGalleryPost'">: @{{ log.info.postUserUsername }}</span>
+		<span v-else-if="log.type === 'deleteChatRoom'">: @{{ log.info.room.name }}</span>
 	</template>
 	<template #icon>
 		<MkAvatar :user="log.user" :class="$style.avatar"/>
diff --git a/packages/frontend/src/pages/chat/message.vue b/packages/frontend/src/pages/chat/message.vue
index be8be7e5d1..975d1a2be9 100644
--- a/packages/frontend/src/pages/chat/message.vue
+++ b/packages/frontend/src/pages/chat/message.vue
@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<MkLoading/>
 		</div>
 		<div v-else>
-			<XMessage :message="message"/>
+			<XMessage :message="message" :isSearchResult="true"/>
 		</div>
 	</MkSpacer>
 </PageWithHeader>
diff --git a/packages/frontend/src/pages/chat/room.info.vue b/packages/frontend/src/pages/chat/room.info.vue
index f4f5e217dd..7e10336fd3 100644
--- a/packages/frontend/src/pages/chat/room.info.vue
+++ b/packages/frontend/src/pages/chat/room.info.vue
@@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 	<hr>
 
-	<MkButton v-if="isOwner" danger @click="del">{{ i18n.ts._chat.deleteRoom }}</MkButton>
+	<MkButton v-if="isOwner || ($i.isAdmin || $i.isModerator)" danger @click="del">{{ i18n.ts._chat.deleteRoom }}</MkButton>
 
 	<MkSwitch v-if="!isOwner" v-model="isMuted">
 		<template #label>{{ i18n.ts._chat.muteThisRoom }}</template>
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 7e73b64bb0..2c97e4b12e 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -2832,10 +2832,13 @@ type ModerationLog = {
 } | {
     type: 'deleteGalleryPost';
     info: ModerationLogPayloads['deleteGalleryPost'];
+} | {
+    type: 'deleteChatRoom';
+    info: ModerationLogPayloads['deleteChatRoom'];
 });
 
 // @public (undocumented)
-export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "forwardAbuseReport", "updateAbuseReportNote", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner", "createSystemWebhook", "updateSystemWebhook", "deleteSystemWebhook", "createAbuseReportNotificationRecipient", "updateAbuseReportNotificationRecipient", "deleteAbuseReportNotificationRecipient", "deleteAccount", "deletePage", "deleteFlash", "deleteGalleryPost"];
+export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "forwardAbuseReport", "updateAbuseReportNote", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner", "createSystemWebhook", "updateSystemWebhook", "deleteSystemWebhook", "createAbuseReportNotificationRecipient", "updateAbuseReportNotificationRecipient", "deleteAbuseReportNotificationRecipient", "deleteAccount", "deletePage", "deleteFlash", "deleteGalleryPost", "deleteChatRoom"];
 
 // @public (undocumented)
 type MuteCreateRequest = operations['mute___create']['requestBody']['content']['application/json'];
diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts
index 9a39e619b7..6d92915c44 100644
--- a/packages/misskey-js/src/consts.ts
+++ b/packages/misskey-js/src/consts.ts
@@ -14,6 +14,7 @@ import type {
 	ReversiGameDetailed,
 	SystemWebhook,
 	UserLite,
+	ChatRoom,
 } from './autogen/models.js';
 
 export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'chatRoomInvitationReceived', 'achievementEarned'] as const;
@@ -165,6 +166,7 @@ export const moderationLogTypes = [
 	'deletePage',
 	'deleteFlash',
 	'deleteGalleryPost',
+	'deleteChatRoom',
 ] as const;
 
 // See: packages/backend/src/core/ReversiService.ts@L410
@@ -437,4 +439,8 @@ export type ModerationLogPayloads = {
 		postUserUsername: string;
 		post: GalleryPost;
 	};
+	deleteChatRoom: {
+		roomId: string;
+		room: ChatRoom;
+	};
 };
diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts
index f04ab25148..ed1d89a685 100644
--- a/packages/misskey-js/src/entities.ts
+++ b/packages/misskey-js/src/entities.ts
@@ -195,6 +195,9 @@ export type ModerationLog = {
 } | {
 	type: 'deleteGalleryPost';
 	info: ModerationLogPayloads['deleteGalleryPost'];
+} | {
+	type: 'deleteChatRoom';
+	info: ModerationLogPayloads['deleteChatRoom'];
 });
 
 export type ServerStats = {