diff --git a/CHANGELOG b/CHANGELOG
index 01fffcc36962f6d90c6a10070cc6a27489fbd3fe..1184ffce76c080e238b64a1a0192b99cc1b19327 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,7 +11,7 @@ v 8.7.0 (unreleased)
   - Fix `signed_in_ip` being set to 127.0.0.1 when using a reverse proxy !3524
   - Improved Markdown rendering performance !3389 (Yorick Peterse)
   - Don't attempt to look up an avatar in repo if repo directory does not exist (Stan Hu)
-  - API: Ability to subscribe and unsubscribe from an issue (Robert Schilling)
+  - API: Ability to subscribe and unsubscribe from issues and merge requests (Robert Schilling)
   - Expose project badges in project settings
   - Preserve time notes/comments have been updated at when moving issue
   - Make HTTP(s) label consistent on clone bar (Stan Hu)
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 20db73ea6c0b13a03610acda10be396bf753443b..16cb892626522d66438831b0fcbaa1e0ca6f35f2 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -606,3 +606,150 @@ Example response:
    },
 ]
 ```
+
+## Subscribe to a merge request
+
+Subscribes to a merge request to receive notification. If the operation is
+successful, status code `201` together with the updated merge request is
+returned. If the user is already subscribed to the merge request, the status
+code `304` is returned. If the project or merge request is not found, status
+code `404` is returned.
+
+```
+POST /projects/:id/merge_requests/:merge_request_id/subscribe
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of a project |
+| `merge_request_id` | integer | yes   | The ID of the merge request |
+
+```bash
+curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/merge_requests/17/subscribe
+```
+
+Example response:
+
+```json
+{
+  "id": 17,
+  "iid": 1,
+  "project_id": 5,
+  "title": "Et et sequi est impedit nulla ut rem et voluptatem.",
+  "description": "Consequatur velit eos rerum optio autem. Quia id officia quaerat dolorum optio. Illo laudantium aut ipsum dolorem.",
+  "state": "opened",
+  "created_at": "2016-04-05T21:42:23.233Z",
+  "updated_at": "2016-04-05T22:11:52.900Z",
+  "target_branch": "ui-dev-kit",
+  "source_branch": "version-1-9",
+  "upvotes": 0,
+  "downvotes": 0,
+  "author": {
+    "name": "Eileen Skiles",
+    "username": "leila",
+    "id": 19,
+    "state": "active",
+    "avatar_url": "http://www.gravatar.com/avatar/39ce4a2822cc896933ffbd68c1470e55?s=80&d=identicon",
+    "web_url": "https://gitlab.example.com/u/leila"
+  },
+  "assignee": {
+    "name": "Celine Wehner",
+    "username": "carli",
+    "id": 16,
+    "state": "active",
+    "avatar_url": "http://www.gravatar.com/avatar/f4cd5605b769dd2ce405a27c6e6f2684?s=80&d=identicon",
+    "web_url": "https://gitlab.example.com/u/carli"
+  },
+  "source_project_id": 5,
+  "target_project_id": 5,
+  "labels": [],
+  "work_in_progress": false,
+  "milestone": {
+    "id": 7,
+    "iid": 1,
+    "project_id": 5,
+    "title": "v2.0",
+    "description": "Corrupti eveniet et velit occaecati dolorem est rerum aut.",
+    "state": "closed",
+    "created_at": "2016-04-05T21:41:40.905Z",
+    "updated_at": "2016-04-05T21:41:40.905Z",
+    "due_date": null
+  },
+  "merge_when_build_succeeds": false,
+  "merge_status": "cannot_be_merged",
+  "subscribed": true
+}
+```
+## Unsubscribe from a merge request
+
+Unsubscribes from a merge request to not receive notifications from that merge
+request. If the operation is successful, status code `201` together with the
+updated merge request is returned. If the user is not subscribed to the merge
+request, the status code `304` is returned. If the project or merge request is
+not found, status code `404` is returned.
+
+```
+POST /projects/:id/merge_requests/:merge_request_id/unsubscribe
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of a project |
+| `merge_request_id` | integer | yes   | The ID of the merge request |
+
+```bash
+curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/merge_requests/17/subscribe
+```
+
+Example response:
+
+```json
+{
+  "id": 17,
+  "iid": 1,
+  "project_id": 5,
+  "title": "Et et sequi est impedit nulla ut rem et voluptatem.",
+  "description": "Consequatur velit eos rerum optio autem. Quia id officia quaerat dolorum optio. Illo laudantium aut ipsum dolorem.",
+  "state": "opened",
+  "created_at": "2016-04-05T21:42:23.233Z",
+  "updated_at": "2016-04-05T22:11:52.900Z",
+  "target_branch": "ui-dev-kit",
+  "source_branch": "version-1-9",
+  "upvotes": 0,
+  "downvotes": 0,
+  "author": {
+    "name": "Eileen Skiles",
+    "username": "leila",
+    "id": 19,
+    "state": "active",
+    "avatar_url": "http://www.gravatar.com/avatar/39ce4a2822cc896933ffbd68c1470e55?s=80&d=identicon",
+    "web_url": "https://gitlab.example.com/u/leila"
+  },
+  "assignee": {
+    "name": "Celine Wehner",
+    "username": "carli",
+    "id": 16,
+    "state": "active",
+    "avatar_url": "http://www.gravatar.com/avatar/f4cd5605b769dd2ce405a27c6e6f2684?s=80&d=identicon",
+    "web_url": "https://gitlab.example.com/u/carli"
+  },
+  "source_project_id": 5,
+  "target_project_id": 5,
+  "labels": [],
+  "work_in_progress": false,
+  "milestone": {
+    "id": 7,
+    "iid": 1,
+    "project_id": 5,
+    "title": "v2.0",
+    "description": "Corrupti eveniet et velit occaecati dolorem est rerum aut.",
+    "state": "closed",
+    "created_at": "2016-04-05T21:41:40.905Z",
+    "updated_at": "2016-04-05T21:41:40.905Z",
+    "due_date": null
+  },
+  "merge_when_build_succeeds": false,
+  "merge_status": "cannot_be_merged",
+  "subscribed": false
+}
+```
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 49911fa2988f9097c6a1d3a68f4872f08dcdbb93..049618c00f71e826c67ac9af5afbca4b7014ff52 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -235,7 +235,7 @@ module API
       # Subscribes to a project issue
       #
       # Parameters:
-      #  id (required) - The ID of a project
+      #  id (required)       - The ID of a project
       #  issue_id (required) - The ID of a project issue
       # Example Request:
       #   POST /projects/:id/issues/:issue_id
@@ -270,7 +270,7 @@ module API
       # Unsubscribes from a project issue
       #
       # Parameters:
-      #  id (required) - The ID of a project
+      #  id (required)       - The ID of a project
       #  issue_id (required) - The ID of a project issue
       # Example Request:
       #   POST /projects/:id/issues/:issue_id/unsubscribe
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 4e7de8867b43aeedd564d088876d1c9cbb037b55..d166484ba548c2c430971d15bb2dcafea8b2991c 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -327,6 +327,42 @@ module API
           issues = ::Kaminari.paginate_array(merge_request.closes_issues(current_user))
           present paginate(issues), with: Entities::Issue, current_user: current_user
         end
+
+        # Subscribes to a merge request
+        #
+        # Parameters:
+        #  id (required)               - The ID of a project
+        #  merge_request_id (required) - The ID of a merge request
+        # Example Request:
+        #   POST /projects/:id/issues/:merge_request_id/subscribe
+        post "#{path}/subscribe" do
+          merge_request = user_project.merge_requests.find(params[:merge_request_id])
+
+          if !merge_request.subscribed?(current_user)
+            merge_request.toggle_subscription(current_user)
+            present merge_request, with: Entities::MergeRequest, current_user: current_user
+          else
+            not_modified!
+          end
+        end
+
+        # Unsubscribes from a merge request
+        #
+        # Parameters:
+        #  id (required)               - The ID of a project
+        #  merge_request_id (required) - The ID of a merge request
+        # Example Request:
+        #   POST /projects/:id/merge_requests/:merge_request_id/unsubscribe
+        post "#{path}/unsubscribe" do
+          merge_request = user_project.merge_requests.find(params[:merge_request_id])
+
+          if merge_request.subscribed?(current_user)
+            merge_request.unsubscribe(current_user)
+            present merge_request, with: Entities::MergeRequest, current_user: current_user
+          else
+            not_modified!
+          end
+        end
       end
     end
   end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 25fa30b2f21d1cb1ac552186e59f8a67ecbf3088..b71c72a382926f7b49515f716edbdf3489a9203f 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -516,6 +516,36 @@ describe API::API, api: true  do
     end
   end
 
+  describe 'POST :id/merge_requests/:merge_request_id/subscribe' do
+    it 'subscribes to a merge request' do
+      post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscribe", admin)
+
+      expect(response.status).to eq(201)
+      expect(json_response['subscribed']).to eq(true)
+    end
+
+    it 'returns 304 if already subscribed' do
+      post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscribe", user)
+
+      expect(response.status).to eq(304)
+    end
+  end
+
+  describe 'POST :id/merge_requests/:merge_request_id/unsubscribe' do
+    it 'unsubscribes from a merge request' do
+      post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/unsubscribe", user)
+
+      expect(response.status).to eq(201)
+      expect(json_response['subscribed']).to eq(false)
+    end
+
+    it 'returns 304 if not subscribed' do
+      post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/unsubscribe", admin)
+
+      expect(response.status).to eq(304)
+    end
+  end
+
   def mr_with_later_created_and_updated_at_time
     merge_request
     merge_request.created_at += 1.hour