diff --git a/src/Entity/Controller/JobItemAccessControlHandler.php b/src/Entity/Controller/JobItemAccessControlHandler.php
index ed88a92..4fec098 100644
--- a/src/Entity/Controller/JobItemAccessControlHandler.php
+++ b/src/Entity/Controller/JobItemAccessControlHandler.php
@@ -9,6 +9,7 @@ namespace Drupal\tmgmt\Entity\Controller;
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Access\AccessResult;
 
 /**
  * Access control handler for the job item entity.
@@ -21,7 +22,13 @@ class JobItemAccessControlHandler extends JobAccessControlHandler {
    * {@inheritdoc}
    */
   protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
-    if ($entity->getJob()) {
+    if ($operation === 'delete') {
+      return AccessResult::allowedIf($entity->isInactive());
+    }
+    else if ($operation == 'abort') {
+      return AccessResult::allowedIf($entity->isActive() || $entity->isNeedsReview());
+    }
+    else if ($entity->getJob()) {
       return $entity->getJob()->access($operation, $account, TRUE);
     }
   }
diff --git a/src/Entity/JobItem.php b/src/Entity/JobItem.php
index 4b70177..17b18cb 100644
--- a/src/Entity/JobItem.php
+++ b/src/Entity/JobItem.php
@@ -31,6 +31,7 @@ use Drupal\Core\Render\Element;
  *     "access" = "Drupal\tmgmt\Entity\Controller\JobItemAccessControlHandler",
  *     "form" = {
  *       "edit" = "Drupal\tmgmt\Form\JobItemForm",
+ *       "abort" = "Drupal\tmgmt\Form\JobItemAbortForm",
  *       "delete" = "Drupal\tmgmt\Form\JobItemDeleteForm"
  *     },
  *     "list_builder" = "Drupal\tmgmt\Entity\ListBuilder\JobItemListBuilder",
@@ -44,6 +45,7 @@ use Drupal\Core\Render\Element;
  *   },
  *   links = {
  *     "canonical" = "/admin/tmgmt/items/{tmgmt_job_item}",
+ *     "abort-form" = "/admin/tmgmt/items/{tmgmt_job_item}/abort",
  *     "delete-form" = "/admin/tmgmt/items/{tmgmt_job_item}/delete",
  *   }
  * )
@@ -461,7 +463,7 @@ class JobItem extends ContentEntityBase implements JobItemInterface {
     }
     $return = $this->setState(static::STATE_REVIEW, $message, $variables, $type);
     // Auto accept the translation if the translator is configured for it.
-    if ($this->getTranslator()->isAutoAccept()) {
+    if ($this->getTranslator()->isAutoAccept() && !$this->isAborted()) {
       $this->acceptTranslation();
     }
     return $return;
@@ -821,6 +823,22 @@ class JobItem extends ContentEntityBase implements JobItemInterface {
   /**
    * {@inheritdoc}
    */
+  public function abortTranslation() {
+    if (!$this->isActive() || !$this->getTranslatorPlugin()) {
+      throw new TMGMTException('Cannot abort job item.');
+    }
+    $this->setState(JobItemInterface::STATE_ABORTED);
+    // Check if this was the last unfinished job item in this job.
+    $job = $this->getJob();
+    if ($job && !$job->isContinuous() && tmgmt_job_check_finished($this->getJobId())) {
+      // Mark the job as finished in case it is a normal job.
+      $job->finished();
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getMessages($conditions = array()) {
     $query = \Drupal::entityQuery('tmgmt_message')
       ->condition('tjiid', $this->id());
diff --git a/src/Entity/ListBuilder/JobItemListBuilder.php b/src/Entity/ListBuilder/JobItemListBuilder.php
index de48ff1..d782395 100644
--- a/src/Entity/ListBuilder/JobItemListBuilder.php
+++ b/src/Entity/ListBuilder/JobItemListBuilder.php
@@ -8,6 +8,7 @@ namespace Drupal\tmgmt\Entity\ListBuilder;
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityListBuilder;
+use Drupal\Core\Url;
 
 /**
  * Provides the views data for the message entity type.
@@ -32,6 +33,15 @@ class JobItemListBuilder extends EntityListBuilder {
         'title' => t('View'),
       );
     }
+    // Display abort button on active or needs review job items.
+    if ($entity->isActive() || $entity->isNeedsReview()) {
+      $operations['abort'] = array(
+        'url' => $entity->urlInfo('abort-form')->setOption('query', array('destination' => Url::fromRoute('<current>')->getInternalPath())),
+        'title' => t('Abort'),
+        'weight' => 10,
+      );
+    }
     return $operations;
   }
+
 }
diff --git a/src/Entity/ListBuilder/JobListBuilder.php b/src/Entity/ListBuilder/JobListBuilder.php
index f77f68d..1b2cbe5 100644
--- a/src/Entity/ListBuilder/JobListBuilder.php
+++ b/src/Entity/ListBuilder/JobListBuilder.php
@@ -36,7 +36,7 @@ class JobListBuilder extends EntityListBuilder {
       );
     }
     if ($entity->isAbortable() && $entity->access('submit')) {
-      $operations['cancel'] = array(
+      $operations['abort'] = array(
         'url' => $entity->urlInfo('abort-form')->setOption('query', array('destination' => Url::fromRoute('<current>')->getInternalPath())),
         'title' => t('Abort'),
         'weight' => 10,
diff --git a/src/Form/JobItemAbortForm.php b/src/Form/JobItemAbortForm.php
new file mode 100644
index 0000000..53c543e
--- /dev/null
+++ b/src/Form/JobItemAbortForm.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\tmgmt\Form\JobItemAbortForm.
+ */
+
+namespace Drupal\tmgmt\Form;
+
+use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\tmgmt\TMGMTException;
+
+/**
+ * Provides a form for deleting a node.
+ */
+class JobItemAbortForm extends ContentEntityConfirmFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getQuestion() {
+    return $this->t('Are you sure you want to abort the job item %title?', array('%title' => $this->entity->label()));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return $this->t('Aborted job items can no longer be accepted. The provider will not be notified.');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCancelUrl() {
+    return $this->entity->toUrl();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    /** @var \Drupal\tmgmt\Entity\JobItem $entity */
+    $entity = $this->entity;
+    try {
+      if (!$entity->abortTranslation()) {
+        foreach ($entity->getMessagesSince() as $message) {
+          /** @var \Drupal\tmgmt\MessageInterface $message */
+          if ($message->getType() == 'debug') {
+            continue;
+          }
+          if ($text = $message->getMessage()) {
+            // We want to persist also the type therefore we will set the
+            // messages directly and not return them.
+            drupal_set_message($text, $message->getType());
+          }
+        }
+      }
+    }
+    catch(TMGMTException $e) {
+      drupal_set_message(t('Job item cannot be aborted: %error.', array(
+        '%error' => $e->getMessage(),
+      )), 'error');
+    }
+    $form_state->setRedirectUrl($this->entity->toUrl());
+  }
+
+}
diff --git a/src/JobItemInterface.php b/src/JobItemInterface.php
index 201aba0..e09a660 100644
--- a/src/JobItemInterface.php
+++ b/src/JobItemInterface.php
@@ -161,6 +161,17 @@ interface JobItemInterface extends ContentEntityInterface {
   public function getTranslatorPlugin();
 
   /**
+   * Attempts to abort the translation job item.
+   *
+   * Already accepted job items can not be aborted. Always use this method if
+   * you want to abort a translation job item.
+   *
+   * @throws \Drupal\tmgmt\TMGMTException
+   *   If fails to abort the job item.
+   */
+  public function abortTranslation();
+
+  /**
    * Array of the data to be translated.
    *
    * The structure is similar to the form API in the way that it is a possibly
diff --git a/src/Tests/TMGMTUiTest.php b/src/Tests/TMGMTUiTest.php
index 96f52d0..c27c071 100644
--- a/src/Tests/TMGMTUiTest.php
+++ b/src/Tests/TMGMTUiTest.php
@@ -753,9 +753,8 @@ class TMGMTUiTest extends EntityTestBase {
   }
 
   /**
-   * Test the deletion of job item.
+   * Test the deletion and abortion of job item.
    *
-   * @todo This will in future check that delete is not allowed.
    * @todo There will be some overlap with Aborting items & testAbortJob.
    */
   function testJobItemDelete() {
@@ -772,21 +771,48 @@ class TMGMTUiTest extends EntityTestBase {
 
     // Add item to the job.
     $item = $job->addItem('test_source', 'test', 1);
+    $item->setState(JobItem::STATE_ACTIVE);
+
+    // Check that there is no delete link on item review form.
+    $this->drupalGet('admin/tmgmt/items/' . $item->id());
+    $this->assertNoFieldById('edit-delete', NULL, 'There is no delete button.');
 
     $this->drupalGet('admin/tmgmt/jobs/' . $job->id());
 
-    // Check for delete link.
-    $this->assertLink('Delete');
+    // Check that there is no delete link.
+    $this->assertNoLink('Delete');
+
+    // Check for abort link.
+    $this->assertLink('Abort');
 
-    $this->clickLink('Delete');
-    $this->assertText(t('Are you sure you want to delete the translation job item @label?', ['@label' => $item->getSourceLabel()]));
+    $this->clickLink('Abort');
+    $this->assertText(t('Are you sure you want to abort the job item test_source:test:1?'));
 
     // Check if cancel button is present or not.
     $this->assertLink('Cancel');
 
-    // Delete the job item.
-    $this->drupalPostForm(NULL, [], t('Delete'));
-    $this->assertText(t('The translation job item @label has been deleted', ['@label' => $item->getSourceLabel()]));
+    // Abort the job item.
+    $this->drupalPostForm(NULL, [], t('Confirm'));
+
+    // Reload job and check its state and state of its item.
+    \Drupal::entityManager()->getStorage('tmgmt_job')->resetCache();
+    $job = Job::load($job->id());
+    $this->assertTrue($job->isFinished());
+    $items = $job->getItems();
+    $item = reset($items);
+    $this->assertTrue($item->isAborted());
+
+    // Check that there is no delete button on item review form.
+    $this->drupalGet('admin/tmgmt/items/' . $item->id());
+    $this->assertNoFieldById('edit-delete', NULL, 'There is delete button.');
+
+    // Check that there is no accept button on item review form.
+    $this->assertNoFieldById('edit-accept', NULL, 'There is no accept button.');
+
+    $this->drupalGet('admin/tmgmt/jobs/' . $job->id());
+
+    // Check that there is no delete link on job overview.
+    $this->assertNoLink('Delete');
   }
 
   /**
diff --git a/tmgmt.module b/tmgmt.module
index 540f3fe..e61b634 100644
--- a/tmgmt.module
+++ b/tmgmt.module
@@ -256,7 +256,7 @@ function tmgmt_job_match_item($source_language, $target_language, $account = NUL
 function tmgmt_job_check_finished($tjid) {
   return !\Drupal::entityQuery('tmgmt_job_item')
     ->condition('tjid', $tjid)
-    ->condition('state', JobItem::STATE_ACCEPTED, '<>')
+    ->condition('state', [JobItem::STATE_ACCEPTED, JobItem::STATE_ABORTED], 'NOT IN')
     ->range(0, 1)
     ->count()
     ->execute();
@@ -686,11 +686,11 @@ function tmgmt_job_request_translation(JobInterface $job) {
 /**
  * Print all messages that occurred since our request to the screen.
  *
- * @param $job
+ * @param \Drupal\tmgmt\JobInterface $job
  *    The translation job for which the message should be written.
  *
- * @return
- *   FALSE if there are message with severity error, TRUE otherwise.
+ * @return bool
+ *    FALSE if there are message with severity error, TRUE otherwise.
  */
 function tmgmt_write_request_messages(JobInterface $job) {
   $errors = FALSE;
diff --git a/tmgmt.routing.yml b/tmgmt.routing.yml
index ee06265..2595c1a 100644
--- a/tmgmt.routing.yml
+++ b/tmgmt.routing.yml
@@ -96,6 +96,13 @@ entity.tmgmt_job_item.delete_form:
   requirements:
     _entity_access: tmgmt_job_item.delete
 
+entity.tmgmt_job_item.abort_form:
+  path: '/admin/tmgmt/items/{tmgmt_job_item}/abort'
+  defaults:
+    _entity_form: tmgmt_job_item.abort
+  requirements:
+    _entity_access: tmgmt_job_item.abort
+
 tmgmt.source_overview:
   path: '/admin/tmgmt/sources/{plugin}/{item_type}'
   defaults:
