diff --git a/CHANGELOG b/CHANGELOG
index 4a299827c1112756699184d29a1e2b152598eb55..b677c9bca0ca57fc07855b78f0184852da2b791e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -35,6 +35,7 @@ v 7.0.0
   - Be more selective when killing stray Sidekiqs
   - Check LDAP user filter during sign-in
   - Remove wall feature (no data loss - you can take it from database)
+  - Detect issues closed by Merge Request description
 
 v 6.9.2
   - Revert the commit that broke the LDAP user filter
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 81875e1be2d2b71247c5f6de9868f1f42b00f696..82876e10446a94ecf730ff7935d9eaf4a31db84e 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -111,22 +111,10 @@ class Commit
     description.present?
   end
 
-  # Regular expression that identifies commit message clauses that trigger issue closing.
-  def issue_closing_regex
-    @issue_closing_regex ||= Regexp.new(Gitlab.config.gitlab.issue_closing_pattern)
-  end
-
   # Discover issues should be closed when this commit is pushed to a project's
   # default branch.
   def closes_issues project
-    md = issue_closing_regex.match(safe_message)
-    if md
-      extractor = Gitlab::ReferenceExtractor.new
-      extractor.analyze(md[0])
-      extractor.issues_for(project)
-    else
-      []
-    end
+    Gitlab::ClosingIssueExtractor.closed_by_message_in_project(safe_message, project)
   end
 
   # Mentionable override.
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index a501870115f24294e7a004f5a8b9fa4f5c8ef138..bfea209bf6dce65900c963169ceb8debba0c0ec3 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -220,7 +220,9 @@ class MergeRequest < ActiveRecord::Base
   # Return the set of issues that will be closed if this merge request is accepted.
   def closes_issues
     if target_branch == project.default_branch
-      commits.map { |c| c.closes_issues(project) }.flatten.uniq.sort_by(&:id)
+      issues = commits.flat_map { |c| c.closes_issues(project) }
+      issues += Gitlab::ClosingIssueExtractor.closed_by_message_in_project(description, project)
+      issues.uniq.sort_by(&:id)
     else
       []
     end
diff --git a/lib/gitlab/closing_issue_extractor.rb b/lib/gitlab/closing_issue_extractor.rb
new file mode 100644
index 0000000000000000000000000000000000000000..90f1370c209e4e06f9f5f6e34527327137863d38
--- /dev/null
+++ b/lib/gitlab/closing_issue_extractor.rb
@@ -0,0 +1,16 @@
+module Gitlab
+  module ClosingIssueExtractor
+    ISSUE_CLOSING_REGEX = Regexp.new(Gitlab.config.gitlab.issue_closing_pattern)
+
+    def self.closed_by_message_in_project(message, project)
+      md = ISSUE_CLOSING_REGEX.match(message)
+      if md
+        extractor = Gitlab::ReferenceExtractor.new
+        extractor.analyze(md[0])
+        extractor.issues_for(project)
+      else
+        []
+      end
+    end
+  end
+end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 81a48699cd8e090515c2b169fe0210d15e2d2a39..1148df87ab7665cd72c2da67fc676b6076e33145 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -105,6 +105,14 @@ describe MergeRequest do
 
       subject.closes_issues.should be_empty
     end
+
+    it 'detects issues mentioned in the description' do
+      issue2 = create(:issue, project: subject.project)
+      subject.description = "Closes ##{issue2.iid}"
+      subject.project.stub(default_branch: subject.target_branch)
+
+      subject.closes_issues.should include(issue2)
+    end
   end
 
   it_behaves_like 'an editable mentionable' do