diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 3512e2b735e06c410b819df1a27cf1fc88f964fd..1ef7a2433dc2278bae3bfe101a6691697e352395 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -86,7 +86,7 @@ class IssuableBaseService < BaseService
     remove_label_ids = attributes.delete(:remove_label_ids)
 
     new_label_ids = base_label_ids
-    new_label_ids = label_ids if label_ids && (merge_all || (add_label_ids.empty? && remove_label_ids.empty?))
+    new_label_ids = label_ids if label_ids && (merge_all || (add_label_ids.blank? && remove_label_ids.blank?))
     new_label_ids |= add_label_ids if add_label_ids
     new_label_ids -= remove_label_ids if remove_label_ids
 
diff --git a/app/services/slash_commands/interpret_service.rb b/app/services/slash_commands/interpret_service.rb
index bff616839761f7467ad95616d91fe127898b3251..74825f308688da8bc4c0a6658e3f6b0c1d0dee60 100644
--- a/app/services/slash_commands/interpret_service.rb
+++ b/app/services/slash_commands/interpret_service.rb
@@ -34,6 +34,12 @@ module SlashCommands
       @updates[:state_event] = 'reopen'
     end
 
+    desc 'Change title'
+    params '<New title>'
+    command :title do |title_param|
+      @updates[:title] = title_param
+    end
+
     desc 'Reassign'
     params '@user'
     command :assign, :reassign do |assignee_param|
diff --git a/doc/workflow/slash_commands.md b/doc/workflow/slash_commands.md
index 3bfc66309baf06dee69f6af1553d6b9f1cb12061..bf5b8ebe1c83fbe7ef16838d0be95b6a6c73aa45 100644
--- a/doc/workflow/slash_commands.md
+++ b/doc/workflow/slash_commands.md
@@ -13,6 +13,7 @@ do.
 |:---------------------------|:--------------------|:-------------|
 | `/close`                   | None                | Close the issue or merge request |
 | `/open`                    | `/reopen`           | Reopen the issue or merge request |
+| `/title <New title>`       | None                | Change title |
 | `/assign @username`        | `/reassign`         | Reassign |
 | `/unassign`                | `/remove_assignee`  | Remove assignee |
 | `/milestone %milestone`    | None                | Change milestone |
@@ -24,5 +25,5 @@ do.
 | `/done`                    | None                | Mark todo as done |
 | `/subscribe`               | None                | Subscribe |
 | `/unsubscribe`             | None                | Unsubscribe |
-| `/due_date`                | None                | Set a due date |
+| `/due_date <YYYY-MM-DD> | <N days>` | None       | Set a due date |
 | `/clear_due_date`          | None                | Remove due date |
diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
index e2339c5e103792fb0156e9b9b637c6d344294494..afb072105cf3c291c9e2bea7ad6c7d81f0598bf5 100644
--- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
@@ -64,10 +64,21 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do
     context 'because the note was commands only' do
       let!(:email_raw) { fixture_file("emails/commands_only_reply.eml") }
 
-      it 'raises a CommandsOnlyNoteError' do
-        expect { receiver.execute }.not_to raise_error
+      context 'and current user cannot update noteable' do
+        it 'raises a CommandsOnlyNoteError' do
+          expect { receiver.execute }.to raise_error(Gitlab::Email::InvalidNoteError)
+        end
       end
 
+      context 'and current user can update noteable' do
+        before do
+          project.team << [user, :developer]
+        end
+
+        it 'raises a CommandsOnlyNoteError' do
+          expect { receiver.execute }.not_to raise_error
+        end
+      end
     end
   end
 
diff --git a/spec/services/slash_commands/interpret_service_spec.rb b/spec/services/slash_commands/interpret_service_spec.rb
index d03c84f59b35737ea8edcd1d01b7e876fe817291..66ebe09189340118c917378a3fbde52ce93eef2a 100644
--- a/spec/services/slash_commands/interpret_service_spec.rb
+++ b/spec/services/slash_commands/interpret_service_spec.rb
@@ -15,6 +15,7 @@ describe SlashCommands::InterpretService, services: true do
       is_expected.to match_array([
         :open, :reopen,
         :close,
+        :title,
         :assign, :reassign,
         :unassign, :remove_assignee,
         :milestone,
@@ -53,6 +54,14 @@ describe SlashCommands::InterpretService, services: true do
       end
     end
 
+    shared_examples 'title command' do
+      it 'populates title: "A brand new title" if content contains /title A brand new title' do
+        changes = service.execute(content, issuable)
+
+        expect(changes).to eq(title: 'A brand new title')
+      end
+    end
+
     shared_examples 'assign command' do
       it 'fetches assignee and populates assignee_id if content contains /assign' do
         changes = service.execute(content, issuable)
@@ -190,6 +199,21 @@ describe SlashCommands::InterpretService, services: true do
       let(:issuable) { merge_request }
     end
 
+    it_behaves_like 'title command' do
+      let(:content) { '/title A brand new title' }
+      let(:issuable) { issue }
+    end
+
+    it_behaves_like 'title command' do
+      let(:content) { '/title A brand new title' }
+      let(:issuable) { merge_request }
+    end
+
+    it_behaves_like 'empty command' do
+      let(:content) { '/title' }
+      let(:issuable) { issue }
+    end
+
     it_behaves_like 'assign command' do
       let(:content) { "/assign @#{user.username}" }
       let(:issuable) { issue }
@@ -200,16 +224,14 @@ describe SlashCommands::InterpretService, services: true do
       let(:issuable) { merge_request }
     end
 
-    it 'does not populate assignee_id if content contains /assign with an unknown user' do
-      changes = service.execute('/assign joe', issue)
-
-      expect(changes).to be_empty
+    it_behaves_like 'empty command' do
+      let(:content) { '/assign @abcd1234' }
+      let(:issuable) { issue }
     end
 
-    it 'does not populate assignee_id if content contains /assign without user' do
-      changes = service.execute('/assign', issue)
-
-      expect(changes).to be_empty
+    it_behaves_like 'empty command' do
+      let(:content) { '/assign' }
+      let(:issuable) { issue }
     end
 
     it_behaves_like 'unassign command' do
diff --git a/spec/support/issuable_slash_commands_shared_examples.rb b/spec/support/issuable_slash_commands_shared_examples.rb
index 824ccb0ddfb1d833e35aa5012165f029917e72c9..4f2e7c3bee882f81a356b41621d9a7397e59d00b 100644
--- a/spec/support/issuable_slash_commands_shared_examples.rb
+++ b/spec/support/issuable_slash_commands_shared_examples.rb
@@ -166,6 +166,43 @@ shared_examples 'issuable record that supports slash commands in its description
       end
     end
 
+    context "with a note changing the #{issuable_type}'s title" do
+      context "when current user can change title of #{issuable_type}" do
+        it "reopens the #{issuable_type}" do
+          page.within('.js-main-target-form') do
+            fill_in 'note[note]', with: "/title Awesome new title"
+            click_button 'Comment'
+          end
+
+          expect(page).not_to have_content '/title'
+          expect(page).to have_content 'Your commands are being executed.'
+
+          expect(issuable.reload.title).to eq 'Awesome new title'
+        end
+      end
+
+      context "when current user cannot change title of #{issuable_type}" do
+        before do
+          logout
+          login_with(guest)
+          visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable)
+        end
+
+        it "does not reopen the #{issuable_type}" do
+          current_title = issuable.title
+          page.within('.js-main-target-form') do
+            fill_in 'note[note]', with: "/title Awesome new title"
+            click_button 'Comment'
+          end
+
+          expect(page).not_to have_content '/title'
+          expect(page).not_to have_content 'Your commands are being executed.'
+
+          expect(issuable.reload.title).not_to eq 'Awesome new title'
+        end
+      end
+    end
+
     context "with a note marking the #{issuable_type} as todo" do
       it "creates a new todo for the #{issuable_type}" do
         page.within('.js-main-target-form') do