diff --git a/db_schema.sql b/db_schema.sql
index e9e0a1175f14e764b3b1b439dd6f6a80b0c50a79..67227e42d561ea7d4b6b821210f6e833aa2ee801 100644
--- a/db_schema.sql
+++ b/db_schema.sql
@@ -296,7 +296,8 @@ CREATE TABLE IF NOT EXISTS `jobs` (
   `last_ping` datetime NOT NULL DEFAULT '',
   `worker` text DEFAULT NULL,
   `data` text NOT NULL DEFAULT '{}',
-  `status` text NOT NULL DEFAULT '{}'
+  `status` text NOT NULL DEFAULT '{}',
+  `canceled` INTEGER DEFAULT 0
 );
 
 CREATE TABLE IF NOT EXISTS `responsible` (
diff --git a/jobs.py b/jobs.py
index 86b5519436c336400aff9b16f1503e759399eb81..9fb807088d39d13a397fc016ef7b66ac841d4a00 100644
--- a/jobs.py
+++ b/jobs.py
@@ -18,9 +18,16 @@ def job_handler(*types, state='finished'):
 def schedule_job(jobtype, data=None, priority=0, queue="default"):
 	if not data:
 		data = {}
-	modify('INSERT INTO jobs (type, priority, queue, data, time_created) VALUES (?, ?, ?, ?, ?)',
+	return modify('INSERT INTO jobs (type, priority, queue, data, time_created) VALUES (?, ?, ?, ?, ?)',
 			jobtype, priority, queue, json.dumps(data, default=date_json_handler), datetime.now())
 
+def cancel_job(job_id):
+	modify('UPDATE jobs SET state = "deleted" WHERE id = ? AND state = "ready"', job_id)
+	modify('UPDATE jobs SET canceled = 1 WHERE id = ?', job_id)
+
+def restart_job(job_id):
+	modify('UPDATE jobs SET state = "ready" WHERE id = ? AND state = "failed" AND NOT canceled', job_id)
+
 @app.route('/internal/jobs/overview')
 @register_navbar('Jobs', iconlib='fa', icon='suitcase')
 @mod_required
@@ -61,12 +68,12 @@ def jobs_action(action, jobid=None):
 		query('UPDATE jobs SET state="deleted" WHERE state = "failed" AND (id = ? OR ? IS NULL)', jobid, jobid)
 	elif action == 'retry_failed':
 		query('UPDATE jobs SET state="ready" WHERE state = "failed" AND (id = ? OR ? IS NULL)', jobid, jobid)
-	elif action == 'copy':
-		if jobid:
-			query("INSERT INTO jobs SELECT NULL, type, priority, queue, 'ready', '', '' , ?, '', NULL, data, '{}' FROM jobs where ID=?;", datetime.now(), jobid)
-	elif action == 'delete':
-		if jobid:
-			query('UPDATE jobs SET state="deleted" WHERE id = ?', jobid)
+	elif action == 'copy' and jobid:
+		query("INSERT INTO jobs SELECT NULL, type, priority, queue, 'ready', '', '' , ?, '', NULL, data, '{}' FROM jobs where ID=?;", datetime.now(), jobid)
+	elif action == 'delete' and jobid:
+		query('UPDATE jobs SET state="deleted" WHERE id = ?', jobid)
+	elif action == 'cancel' and jobid:
+		cancel_job(jobid)
 	return redirect(request.values.get('ref', url_for('jobs_overview')))
 
 def jobs_api_token_required(func):
@@ -118,7 +125,10 @@ def jobs_ping(id):
 			func(id, job['type'], json.loads(job['data']), state, json.loads(job['status']))
 		except Exception:
 			traceback.print_exc()
-	return 'OK', 200
+	if job['canceled']:
+		return 'Job canceled', 205
+	else:
+		return 'OK', 200
 
 @app.route('/internal/jobs/api/worker/<hostname>/schedule', methods=['POST'])
 @jobs_api_token_required
diff --git a/server.py b/server.py
index 1c536d032663ddd8d99a9f5de492750dfc8a40bc..b762ae168c636372c6d79789e27bcde4839bdebe 100644
--- a/server.py
+++ b/server.py
@@ -486,7 +486,7 @@ def dbstatus():
 def date_json_handler(obj):
 	return obj.isoformat() if hasattr(obj, 'isoformat') else obj
 
-from jobs import job_handler, schedule_job
+from jobs import job_handler, schedule_job, cancel_job, restart_job
 from edit import edit_handler
 import feeds
 import importer
diff --git a/templates/jobs_overview.html b/templates/jobs_overview.html
index 87aa4a070b58dfae214246fce93216f79f8fa1a2..2f099a445614be7094d49104c313f91d6f0b5a32 100644
--- a/templates/jobs_overview.html
+++ b/templates/jobs_overview.html
@@ -192,7 +192,7 @@
 								<td>{{i.priority}}</td>
 								<td>{{i.worker}}</td>
 								<td>{{i.last_ping}}</td>
-								<td>{{i.state}}</td>
+								<td>{{i.state}}{% if i.canceled %} (canceled) {% endif %}</td>
 								<td>{{i.time_created}}</td>
 								<td>{{i.time_finished}}</td>
 								<td>{{i.time_scheduled}}</td>
@@ -223,6 +223,12 @@
 													<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
 												</a>
 											</li>
+										{% elif i.state == "running" %}
+											<li>
+												<a class="btn btn-default" {% if i.canceled %}disabled="disabled"{% endif %} href="{{url_for('jobs_action', action='cancel', jobid=i.id, ref=request.url)}}" title="Abbrechen" style="background-color: red;">
+													<span class="glyphicon glyphicon-stop" aria-hidden="true"></span>
+												</a>
+											</li>
 										{% endif %}
 									{% endif %}
 									</ul>