diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index cb62bea..f3a5a63 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -93,7 +93,7 @@ function comment_help($path, $arg) {
       $output .= '<dt>' . t('Default and custom settings') . '</dt>';
       $output .= '<dd>' . t("Each <a href='@content-type'>content type</a> can have its own default comment settings configured as: <em>Open</em> to allow new comments, <em>Hidden</em> to hide existing comments and prevent new comments, or <em>Closed</em> to view existing comments, but prevent new comments. These defaults will apply to all new content created (changes to the settings on existing content must be done manually). Other comment settings can also be customized per content type, and can be overridden for any given item of content. When a comment has no replies, it remains editable by its author, as long as the author has a user account and is logged in.", array('@content-type' => url('admin/structure/types'))) . '</dd>';
       $output .= '<dt>' . t('Comment approval') . '</dt>';
-      $output .= '<dd>' . t("Comments from users who have the <em>Skip comment approval</em> permission are published immediately. All other comments are placed in the <a href='@comment-approval'>Unapproved comments</a> queue, until a user who has permission to <em>Administer comments</em> publishes or deletes them. Published comments can be bulk managed on the <a href='@admin-comment'>Published comments</a> administration page.", array('@comment-approval' => url('admin/content/comment/approval'), '@admin-comment' => url('admin/content/comment'))) . '</dd>';
+      $output .= '<dd>' . t("Comments from users who have the <em>Skip comment approval</em> permission are published immediately. All other comments are placed in the <a href='@comment-approval'>Unpublished comments</a> queue, until a user who has permission to <em>Administer comments</em> publishes or deletes them. Published comments can be bulk managed on the <a href='@admin-comment'>Published comments</a> administration page.", array('@comment-approval' => url('admin/content/comment/approval'), '@admin-comment' => url('admin/content/comment'))) . '</dd>';
       $output .= '</dl>';
       return $output;
   }
@@ -194,7 +194,7 @@ function comment_menu() {
     'type' => MENU_DEFAULT_LOCAL_TASK,
   );
   $items['admin/content/comment/approval'] = array(
-    'title' => 'Unapproved comments',
+    'title' => 'Unpublished comments',
     'title callback' => 'comment_count_unpublished',
     'route_name' => 'comment.admin_approval',
     'type' => MENU_LOCAL_TASK,
@@ -214,10 +214,15 @@ function comment_menu() {
     'type' => MENU_LOCAL_TASK,
     'route_name' => 'comment.edit_page',
   );
-  $items['comment/%comment/approve'] = array(
-    'title' => 'Approve',
+  $items['comment/%comment/publish'] = array(
+    'title' => 'Publish',
     'weight' => 10,
-    'route_name' => 'comment.approve',
+    'route_name' => 'comment.publish',
+  );
+  $items['comment/%comment/unpublish'] = array(
+    'title' => 'Unpublish',
+    'weight' => 10,
+    'route_name' => 'comment.unpublish',
   );
   $items['comment/%comment/delete'] = array(
     'title' => 'Delete',
@@ -247,13 +252,13 @@ function comment_menu_alter(&$items) {
 }
 
 /**
- * Returns a menu title which includes the number of unapproved comments.
+ * Returns a menu title which includes the number of unpublished comments.
  */
 function comment_count_unpublished() {
   $count = db_query('SELECT COUNT(cid) FROM {comment} WHERE status = :status', array(
     ':status' => COMMENT_NOT_PUBLISHED,
   ))->fetchField();
-  return t('Unapproved comments (@count)', array('@count' => $count));
+  return t('Unpublished comments (@count)', array('@count' => $count));
 }
 
 /**
@@ -884,12 +889,20 @@ function comment_links(Comment $comment, EntityInterface $node) {
         'html' => TRUE,
       );
     }
-    if ($comment->status->value == COMMENT_NOT_PUBLISHED && $comment->access('approve')) {
-      $links['comment-approve'] = array(
-        'title' => t('approve'),
-        'href' => "comment/{$comment->id()}/approve",
+    if ($comment->status->value == COMMENT_NOT_PUBLISHED && $comment->access('publish')) {
+      $links['comment-publish'] = array(
+        'title' => t('publish'),
+        'href' => "comment/{$comment->id()}/publish",
+        'html' => TRUE,
+        'query' => array('token' => drupal_get_token("comment/{$comment->id()}/publish")),
+      );
+    }
+    if ($comment->status->value == COMMENT_PUBLISHED && $comment->access('unpublish')) {
+      $links['comment-unpublish'] = array(
+        'title' => t('unpublish'),
+        'href' => "comment/{$comment->id()}/unpublish",
         'html' => TRUE,
-        'query' => array('token' => drupal_get_token("comment/{$comment->id()}/approve")),
+        'query' => array('token' => drupal_get_token("comment/{$comment->id()}/unpublish")),
       );
     }
     if (empty($links)) {
diff --git a/core/modules/comment/comment.routing.yml b/core/modules/comment/comment.routing.yml
index 305d7b2..69fe5cf 100644
--- a/core/modules/comment/comment.routing.yml
+++ b/core/modules/comment/comment.routing.yml
@@ -23,13 +23,21 @@ comment.edit_page:
   requirements:
     _entity_access: 'comment.update'
 
-comment.approve:
-  path: '/comment/{comment}/approve'
+comment.publish:
+  pattern: '/comment/{comment}/publish'
   defaults:
-    _content: '\Drupal\comment\Controller\CommentController::commentApprove'
+    _content: '\Drupal\comment\Controller\CommentController::commentPublish'
     entity_type: 'comment'
   requirements:
-    _entity_access: 'comment.approve'
+    _entity_access: 'comment.publish'
+
+comment.unpublish:
+  pattern: '/comment/{comment}/unpublish'
+  defaults:
+    _content: '\Drupal\comment\Controller\CommentController::commentUnpublish'
+    entity_type: 'comment'
+  requirements:
+    _entity_access: 'comment.unpublish'
 
 comment.permalink:
   path: '/comment/{comment}'
diff --git a/core/modules/comment/comment.views.inc b/core/modules/comment/comment.views.inc
index 79602d2..1001e18 100644
--- a/core/modules/comment/comment.views.inc
+++ b/core/modules/comment/comment.views.inc
@@ -229,17 +229,17 @@ function comment_views_data() {
   );
 
   $data['comment']['status'] = array(
-    'title' => t('Approved status'),
-    'help' => t('Whether the comment is approved (or still in the moderation queue).'),
+    'title' => t('Published status'),
+    'help' => t('Whether the comment is published (or still in the moderation queue).'),
     'field' => array(
       'id' => 'boolean',
       'output formats' => array(
-        'approved-not-approved' => array(t('Approved'), t('Not Approved')),
+        'published-not-published' => array(t('Published'), t('Not Published')),
       ),
     ),
     'filter' => array(
       'id' => 'boolean',
-      'label' => t('Approved comment status'),
+      'label' => t('Published comment status'),
       'type' => 'yes-no',
     ),
     'sort' => array(
diff --git a/core/modules/comment/lib/Drupal/comment/CommentAccessController.php b/core/modules/comment/lib/Drupal/comment/CommentAccessController.php
index 800991f..cc114ee 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentAccessController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentAccessController.php
@@ -35,10 +35,13 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
         return user_access('administer comments', $account);
         break;
 
-      case 'approve':
+      case 'publish':
         return user_access('administer comments', $account);
         break;
-    }
+
+      case 'unpublish':
+        return user_access('administer comments', $account);
+        break;    }
   }
 
   /**
diff --git a/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php b/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php
index 2470b2a..f832199 100644
--- a/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php
+++ b/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php
@@ -87,13 +87,13 @@ public static function create(ContainerInterface $container) {
    * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
    * @return \Symfony\Component\HttpFoundation\RedirectResponse.
    */
-  public function commentApprove(Request $request, CommentInterface $comment) {
+  public function commentPublish(Request $request, CommentInterface $comment) {
     // @todo CRSF tokens are validated in the content controller until it gets
     //   moved to the access layer:
     //   Integrate CSRF link token directly into routing system:
     //   https://drupal.org/node/1798296.
     $token = $request->query->get('token');
-    if (!isset($token) || !$this->csrfToken->validate($token, 'comment/' . $comment->id() . '/approve')) {
+    if (!isset($token) || !drupal_valid_token($token, 'comment/' . $comment->id() . '/publish')) {
       throw new AccessDeniedHttpException();
     }
 
@@ -108,6 +108,31 @@ public function commentApprove(Request $request, CommentInterface $comment) {
   }
 
   /**
+   * Unpublishes the specified comment.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request object.
+   * @param \Drupal\comment\CommentInterface $comment
+   *   A comment entity.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+   * @return \Symfony\Component\HttpFoundation\RedirectResponse.
+   */
+  public function commentUnpublish(Request $request, CommentInterface $comment) {
+    // @todo CRSF tokens are validated in the content controller until it gets
+    //   moved to the access layer:
+    //   Integrate CSRF link token directly into routing system:
+    //   https://drupal.org/node/1798296.
+    $token = $request->query->get('token');
+    if (!isset($token) || !drupal_valid_token($token, 'comment/' . $comment->id() . '/unpublish')) {
+      throw new AccessDeniedHttpException();
+    }
+
+    $comment->status->value = COMMENT_NOT_PUBLISHED;
+    $comment->save();
+  }
+
+  /**
    * Redirects comment links to the correct page depending on comment settings.
    *
    * Since comments are paged there is no way to guarantee which page a comment
diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/views/field/LinkApprove.php b/core/modules/comment/lib/Drupal/comment/Plugin/views/field/LinkApprove.php
index 78090c8..53a6c30 100644
--- a/core/modules/comment/lib/Drupal/comment/Plugin/views/field/LinkApprove.php
+++ b/core/modules/comment/lib/Drupal/comment/Plugin/views/field/LinkApprove.php
@@ -32,12 +32,12 @@ protected function renderLink($data, ResultRow $values) {
       return;
     }
 
-    $text = !empty($this->options['text']) ? $this->options['text'] : t('approve');
+    $text = !empty($this->options['text']) ? $this->options['text'] : t('publish');
     $cid =  $this->getValue($values, 'cid');
 
     $this->options['alter']['make_link'] = TRUE;
-    $this->options['alter']['path'] = "comment/" . $cid . "/approve";
-    $this->options['alter']['query'] = drupal_get_destination() + array('token' => drupal_get_token("comment/$cid/approve"));
+    $this->options['alter']['path'] = "comment/" . $cid . "/publish";
+    $this->options['alter']['query'] = drupal_get_destination() + array('token' => drupal_get_token("comment/$cid/publish"));
 
     return $text;
   }
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php
index 6c0a90a..b6bee65 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php
@@ -64,16 +64,30 @@ function testApprovalAdminInterface() {
     $comments[] = $this->postComment($this->node, $this->randomName(), $this->randomName(), TRUE);
     $comments[] = $this->postComment($this->node, $this->randomName(), $this->randomName(), TRUE);
 
+    // Unpublish comment.
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('comment/1/unpublish');
+    $this->assertResponse(403, 'Forged comment unpublish was denied.');
+    $this->drupalGet('comment/1/unpublish', array('query' => array('token' => 'forged')));
+    $this->assertResponse(403, 'Forged comment unpublish was denied.');
+    $this->drupalGet('node/' . $this->node->id());
+    $this->clickLink(t('unpublish'));
+    $this->drupalLogout();
+
+    $this->drupalGet('node/' . $this->node->id());
+    $this->assertFalse($this->commentExists($anonymous_comment4), 'Comment was unpublished.');
+
     // Publish multiple comments in one operation.
     $this->drupalLogin($this->admin_user);
     $this->drupalGet('admin/content/comment/approval');
-    $this->assertText(t('Unapproved comments (@count)', array('@count' => 2)), 'Two unapproved comments waiting for approval.');
+    $this->assertText(t('Unpublished comments (@count)', array('@count' => 3)), 'Three unpublished comments waiting for approval.');
     $edit = array(
       "comments[{$comments[0]->id()}]" => 1,
       "comments[{$comments[1]->id()}]" => 1,
+      "comments[{$anonymous_comment4->id()}]" => 1,
     );
-    $this->drupalPostForm(NULL, $edit, t('Update'));
-    $this->assertText(t('Unapproved comments (@count)', array('@count' => 0)), 'All comments were approved.');
+    $this->drupalPost(NULL, $edit, t('Update'));
+    $this->assertText(t('Unpublished comments (@count)', array('@count' => 0)), 'All comments were published.');
 
     // Delete multiple comments in one operation.
     $edit = array(
@@ -116,17 +130,30 @@ function testApprovalNodeInterface() {
 
     $this->assertFalse($this->commentExists($anonymous_comment4), 'Anonymous comment was not published.');
 
-    // Approve comment.
+    // Publish comment.
     $this->drupalLogin($this->admin_user);
-    $this->drupalGet('comment/1/approve');
+    $this->drupalGet('comment/1/publish');
     $this->assertResponse(403, 'Forged comment approval was denied.');
-    $this->drupalGet('comment/1/approve', array('query' => array('token' => 'forged')));
+    $this->drupalGet('comment/1/publish', array('query' => array('token' => 'forged')));
     $this->assertResponse(403, 'Forged comment approval was denied.');
     $this->drupalGet('node/' . $this->node->id());
-    $this->clickLink(t('approve'));
+    $this->clickLink(t('publish'));
     $this->drupalLogout();
 
     $this->drupalGet('node/' . $this->node->id());
     $this->assertTrue($this->commentExists($anonymous_comment4), 'Anonymous comment visible.');
+
+    // Unpublish comment.
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('comment/1/unpublish');
+    $this->assertResponse(403, 'Forged comment unapproval was denied.');
+    $this->drupalGet('comment/1/unpublish', array('query' => array('token' => 'forged')));
+    $this->assertResponse(403, 'Forged comment unapproval was denied.');
+    $this->drupalGet('node/' . $this->node->id());
+    $this->clickLink(t('unpublish'));
+    $this->drupalLogout();
+
+    $this->drupalGet('node/' . $this->node->id());
+    $this->assertFalse($this->commentExists($anonymous_comment4), 'Comment was unpublished.');
   }
 }
