diff --git a/CHANGELOG b/CHANGELOG
index 5b91ee1159c5ac6ca20013cb5e6e3e01925c7dc8..6a7c314f9f8e1a0b4637d0703434bd49f3de5121 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -34,6 +34,7 @@ v 8.10.0 (unreleased)
   - Add basic system information like memory and disk usage to the admin panel
   - Don't garbage collect commits that have related DB records like comments
   - More descriptive message for git hooks and file locks
+  - Handle custom Git hook result in GitLab UI
 
 v 8.9.5 (unreleased)
   - Improve the request / withdraw access button. !4860
diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb
index 9aaf5a5e561804560d5e962afc62905a57b21b6a..3bec66cea88555b7fd4b18187c3312daa1d2a0d5 100644
--- a/app/services/merge_requests/merge_service.rb
+++ b/app/services/merge_requests/merge_service.rb
@@ -36,10 +36,13 @@ module MergeRequests
 
       commit_id = repository.merge(current_user, merge_request.source_sha, merge_request.target_branch, options)
       merge_request.update(merge_commit_sha: commit_id)
+    rescue GitHooksService::PreReceiveError => e
+      merge_request.update(merge_error: e.message)
+      false
     rescue StandardError => e
       merge_request.update(merge_error: "Something went wrong during merge")
       Rails.logger.error(e.message)
-      return false
+      false
     end
 
     def after_merge
diff --git a/lib/gitlab/git/hook.rb b/lib/gitlab/git/hook.rb
index 5415f4844d3d848c41403fdca6ac51306c190eab..420c6883c45a0913da78ebdb87738cdb1812319f 100644
--- a/lib/gitlab/git/hook.rb
+++ b/lib/gitlab/git/hook.rb
@@ -41,7 +41,7 @@ module Gitlab
           chdir: repo_path
         }
 
-        Open3.popen3(vars, path, options) do |stdin, _, stderr, wait_thr|
+        Open3.popen3(vars, path, options) do |stdin, stdout, stderr, wait_thr|
           exit_status = true
           stdin.sync = true
 
@@ -60,7 +60,7 @@ module Gitlab
 
           unless wait_thr.value == 0
             exit_status = false
-            exit_message = stderr.gets
+            exit_message = retrieve_error_message(stderr, stdout)
           end
         end
 
@@ -76,6 +76,11 @@ module Gitlab
 
         [status, nil]
       end
+
+      def retrieve_error_message(stderr, stdout)
+        err_message = stderr.gets
+        err_message.blank? ? stdout.gets : err_message
+      end
     end
   end
 end
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index 1b0396eb6865c97fca3bfeb4b104d6792c1ceb7a..2f72cd600715689686dc4ad10b81d5c19d4afcaa 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -65,6 +65,16 @@ describe MergeRequests::MergeService, services: true do
 
         expect(merge_request.merge_error).to eq("Something went wrong during merge")
       end
+
+      it 'saves error if there is an PreReceiveError exception' do
+        allow(service).to receive(:repository).and_raise(GitHooksService::PreReceiveError, "error")
+
+        allow(service).to receive(:execute_hooks)
+
+        service.execute(merge_request)
+
+        expect(merge_request.merge_error).to eq("error")
+      end
     end
   end
 end