diff --git a/src/contents/ui/room-settings/RoomSettingsPage.qml b/src/contents/ui/room-settings/RoomSettingsPage.qml
--- a/src/contents/ui/room-settings/RoomSettingsPage.qml
+++ b/src/contents/ui/room-settings/RoomSettingsPage.qml
@@ -26,6 +26,27 @@
   }
   property var roomDisplayName: roomNameProvider.name
   property var customTagIds: room.tagIds.filter(k => k.startsWith('u.'))
+  property var editingName: false
+  property var submittingName: false
+  property var submitName: Kazv.AsyncHandler {
+    trigger: () => {
+      roomSettingsPage.submittingName = true;
+      return roomSettingsPage.room.setName(roomNameEdit.text);
+    }
+    onResolved: (success, data) => {
+      roomSettingsPage.submittingName = false;
+      if (success) {
+        roomSettingsPage.editingName = false;
+      } else {
+        showPassiveNotification(l10n.get('room-settings-set-name-failed-prompt', {
+          room: room.roomId,
+          errorCode: data.errorCode,
+          errorMsg: data.error,
+        }));
+      }
+    }
+  }
+
   property var editingTopic: false
   property var submittingTopic: false
   property var submitTopic: Kazv.AsyncHandler {
@@ -129,17 +150,53 @@
     ColumnLayout {
       Layout.fillWidth: true
       Layout.alignment: Qt.AlignHCenter
-      Label {
-        objectName: 'roomNameLabel'
-        Layout.alignment: Qt.AlignHCenter
-        text: !!room.name ? room.name : room.roomId
-      }
       Label {
         objectName: 'roomIdLabel'
         Layout.alignment: Qt.AlignHCenter
         font: Kirigami.Theme.smallFont
         text: room.roomId
-        visible: !!room.name
+      }
+    }
+    RowLayout {
+      visible: !roomSettingsPage.editingName
+      Kazv.SelectableText {
+        objectName: 'roomNameLabel'
+        text: room.name || l10n.get('room-settings-name-missing')
+        wrapMode: Text.Wrap
+        Kirigami.Theme.colorGroup: !!room.name ? Kirigami.Theme.Normal : Kirigami.Theme.Inactive
+        Layout.fillWidth: true
+      }
+      Button {
+        Layout.alignment: Qt.AlignTop
+        objectName: 'editNameButton'
+        text: l10n.get('room-settings-edit-name-action')
+        onClicked: {
+          roomNameEdit.text = room.name;
+          roomSettingsPage.editingName = true;
+        }
+      }
+    }
+    RowLayout {
+      visible: roomSettingsPage.editingName
+      TextArea {
+        id: roomNameEdit
+        objectName: 'roomNameEdit'
+        Layout.fillWidth: true
+        wrapMode: Text.Wrap
+      }
+      Button {
+        Layout.alignment: Qt.AlignTop
+        objectName: 'saveNameButton'
+        enabled: !roomSettingsPage.submittingName
+        text: l10n.get('room-settings-save-name-action')
+        onClicked: roomSettingsPage.submitName.call()
+      }
+      Button {
+        Layout.alignment: Qt.AlignTop
+        objectName: 'discardNameButton'
+        enabled: !roomSettingsPage.submittingName
+        text: l10n.get('room-settings-discard-name-action')
+        onClicked: roomSettingsPage.editingName = false
       }
     }
     RowLayout {
diff --git a/src/l10n/cmn-Hans/100-ui.ftl b/src/l10n/cmn-Hans/100-ui.ftl
--- a/src/l10n/cmn-Hans/100-ui.ftl
+++ b/src/l10n/cmn-Hans/100-ui.ftl
@@ -106,10 +106,15 @@
 room-settings-not-encrypted = 本房间中的消息没有端对端加密。
 room-settings-encryption-enabled-notification = 本房间中的加密已经启用。
 room-settings-encryption-failed-to-enable-notification = 不能在本房间中启用加密。错误代码:{ $errorCode }。错误讯息:{ $errorMsg }。
+room-settings-name-missing = 这个房间没有名字。
 room-settings-topic-missing = 这个房间没有话题。
+room-settings-edit-name-action = 编辑房间名字
 room-settings-edit-topic-action = 编辑话题
+room-settings-save-name-action = 保存房间名字
 room-settings-save-topic-action = 保存话题
+room-settings-discard-name-action = 放弃房间名字
 room-settings-discard-topic-action = 放弃话题
+room-settings-set-name-failed-prompt = 不能设置房间名字。错误代码:{ $errorCode }。错误讯息:{ $errorMsg }。
 room-settings-set-topic-failed-prompt = 不能设置话题。错误代码:{ $errorCode }。错误讯息:{ $errorMsg }。
 room-sticker-packs-action = 贴纸包...
 room-sticker-packs-page-title = { $room } 中的贴纸包
diff --git a/src/l10n/en/100-ui.ftl b/src/l10n/en/100-ui.ftl
--- a/src/l10n/en/100-ui.ftl
+++ b/src/l10n/en/100-ui.ftl
@@ -110,10 +110,15 @@
 room-settings-not-encrypted = Messages in this room are not end-to-end-encrypted.
 room-settings-encryption-enabled-notification = Encryption is now enabled in this room.
 room-settings-encryption-failed-to-enable-notification = Cannot enable encryption in this room. Error code: { $errorCode }. Error message: { $errorMsg }.
+room-settings-name-missing = This room dose not have a name.
 room-settings-topic-missing = This room does not have a topic.
+room-settings-edit-name-action = Edit name
 room-settings-edit-topic-action = Edit topic
+room-settings-save-name-action = Save name
 room-settings-save-topic-action = Save topic
+room-settings-discard-name-action = Discard name
 room-settings-discard-topic-action = Discard topic
+room-settings-set-name-failed-prompt = Cannot set name. Error code: { $errorCode }. Error message: { $errorMsg }.
 room-settings-set-topic-failed-prompt = Cannot set topic. Error code: { $errorCode }. Error message: { $errorMsg }.
 room-sticker-packs-action = Sticker packs...
 room-sticker-packs-page-title = Sticker packs in { $room }
diff --git a/src/matrix-room.hpp b/src/matrix-room.hpp
--- a/src/matrix-room.hpp
+++ b/src/matrix-room.hpp
@@ -154,6 +154,8 @@
 
     Q_INVOKABLE MatrixPromise *postReadReceipt(const QString &eventId) const;
 
+    Q_INVOKABLE MatrixPromise *setName(const QString &newName) const;
+
     Q_INVOKABLE MatrixPromise *setTopic(const QString &newTopic) const;
 
     /**
diff --git a/src/matrix-room.cpp b/src/matrix-room.cpp
--- a/src/matrix-room.cpp
+++ b/src/matrix-room.cpp
@@ -564,6 +564,11 @@
     return new MatrixPromise(m_room.postReceipt(eventId.toStdString()));
 }
 
+MatrixPromise *MatrixRoom::setName(const QString &newName) const
+{
+    return new MatrixPromise(m_room.setName(newName.toStdString()));
+}
+
 MatrixPromise *MatrixRoom::setTopic(const QString &newTopic) const
 {
     return new MatrixPromise(m_room.setTopic(newTopic.toStdString()));
diff --git a/src/tests/quick-tests/tst_RoomSettingsPage.qml b/src/tests/quick-tests/tst_RoomSettingsPage.qml
--- a/src/tests/quick-tests/tst_RoomSettingsPage.qml
+++ b/src/tests/quick-tests/tst_RoomSettingsPage.qml
@@ -56,6 +56,7 @@
       },
       count: 5
     }),
+    setName: mockHelper.promise(),
   })
 
   property var roomWithoutName: Helpers.factory.room({
@@ -122,6 +123,7 @@
     function initTestCase() {
       pageJoined.contentItem.clip = false;
       pageWithTopic.contentItem.clip = false;
+      pageWithMembers.contentItem.clip = false;
     }
 
     function init() {
@@ -129,6 +131,8 @@
       pageJoined.editingTopic = false;
       pageWithTopic.submittingTopic = false;
       pageWithTopic.editingTopic = false;
+      pageWithMembers.submittingName = false;
+      pageWithMembers.editingName = false;
       mockHelper.clearAll();
     }
 
@@ -200,14 +204,13 @@
       const idLabel = findChild(pageWithMembers, 'roomIdLabel');
       verify(nameLabel.text === 'some name');
       verify(idLabel.text === '!someid:example.com');
-      verify(idLabel.visible);
     }
 
     function test_roomWithoutName() {
       const nameLabel = findChild(pageWithoutName, 'roomNameLabel');
-      const idLabel = findChild(pageWithoutName, 'roomIdLabel');
-      verify(nameLabel.text === '!someid:example.com');
-      verify(!idLabel.visible)
+      const idLabel = findChild(pageWithMembers, 'roomIdLabel');
+      compare(nameLabel.text, l10n.get('room-settings-name-missing'));
+      compare(idLabel.text, '!someid:example.com');
     }
 
     function test_roomWithoutTopic() {
@@ -284,5 +287,60 @@
       tryVerify(() => textArea.visible);
       verify(textArea.text === '');
     }
+
+    function test_editRoomName() {
+      const editButton = findChild(pageWithMembers, 'editNameButton');
+      mouseClick(editButton);
+      const textArea = findChild(pageWithMembers, 'roomNameEdit');
+      tryVerify(() => textArea.visible);
+      verify(textArea.text === 'some name');
+      textArea.text = 'other name';
+      const saveNameButton = findChild(pageWithMembers, 'saveNameButton');
+      verify(saveNameButton.visible);
+      verify(saveNameButton.enabled);
+      const discardNameButton = findChild(pageWithMembers, 'discardNameButton');
+      verify(discardNameButton.visible);
+      verify(discardNameButton.enabled);
+      mouseClick(saveNameButton);
+      tryVerify(() => roomWithMembers.setName.calledTimes() === 1);
+      compare(roomWithMembers.setName.lastArgs()[0], 'other name');
+      verify(!saveNameButton.enabled);
+      verify(!discardNameButton.enabled);
+
+      roomWithMembers.setName.lastRetVal().resolve(true, {});
+      tryVerify(() => editButton.visible);
+      verify(!saveNameButton.visible);
+    }
+
+    function test_editRoomNameFailed() {
+      const editButton = findChild(pageWithMembers, 'editNameButton');
+      mouseClick(editButton);
+      const textArea = findChild(pageWithMembers, 'roomNameEdit');
+      tryVerify(() => textArea.visible);
+      verify(textArea.text === 'some name');
+      textArea.text = 'other name';
+      const saveNameButton = findChild(pageWithMembers, 'saveNameButton');
+      mouseClick(saveNameButton);
+      tryVerify(() => roomWithMembers.setName.calledTimes() === 1);
+      roomWithMembers.setName.lastRetVal().resolve(false, {});
+      verify(saveNameButton.enabled);
+      verify(textArea.visible);
+    }
+
+    function test_editRoomNameDiscard() {
+      const editButton = findChild(pageWithMembers, 'editNameButton');
+      mouseClick(editButton);
+      const textArea = findChild(pageWithMembers, 'roomNameEdit');
+      tryVerify(() => textArea.visible);
+      verify(textArea.text === 'some name');
+      textArea.text = 'other name';
+      const discardNameButton = findChild(pageWithMembers, 'discardNameButton');
+      mouseClick(discardNameButton);
+      compare(roomWithMembers.setName.calledTimes(), 0);
+      verify(!textArea.visible);
+      mouseClick(editButton);
+      tryVerify(() => textArea.visible);
+      verify(textArea.text === 'some name');
+    }
   }
 }