diff --git a/mo/web/org_users.py b/mo/web/org_users.py
index 683c0f792e14eb1bed26454724905c16a9ba0dbd..47b7991966d82aa10ab48430adb45fc4807cc3fa 100644
--- a/mo/web/org_users.py
+++ b/mo/web/org_users.py
@@ -664,3 +664,93 @@ def org_orgs_import():
             year=mo.config.CURRENT_YEAR if form.only_this_year.data else None
         )
     return generic_import_page(form, imp, url_for('org_orgs_import'), template='org_global_orgs_import.html')
+
+
+class ConfirmDeleteForm(FlaskForm):
+    delete = SubmitField('Potvrdit smazání')
+
+
+@app.route('/org/user/<int:user_id>/delete', methods=('GET', 'POST'))
+def org_user_delete(user_id: int):
+    if not g.user.is_admin:
+        raise werkzeug.exceptions.Forbidden()
+
+    sess = db.get_session()
+    user = sess.query(db.User).get(user_id)
+    if not user:
+        raise werkzeug.exceptions.NotFound()
+
+    warnings = []
+    errors = []
+
+    pants = sess.query(db.Participant).filter_by(user=user).all()
+    for pant in pants:
+        warnings.append(f'Účastní se {pant.year}. ročníku')
+
+    pions = (sess.query(db.Participation)
+             .filter_by(user=user)
+             # .options(joinedload(db.Participation.contest, db.Participation.contest.round))
+             .all())
+    for pion in pions:
+        warnings.append(f'Účastní se kola {pion.contest.round.round_code()}')
+
+    num_roles = sess.query(db.UserRole).filter_by(user=user).count()
+    if num_roles > 0:
+        warnings.append(f'Má přidělené role ({num_roles})')
+
+    sols = (sess.query(db.Solution)
+            .filter_by(user=user)
+            # .options(joinedload(db.Solution.task, db.Solution.task.round))
+            .all())
+    for sol in sols:
+        errors.append(f'Odevzdal úlohu {sol.task.code} v kole {sol.task.round.round_code()}')
+
+    num_papers = sess.query(db.Paper).filter_by(for_user_obj=user).count()
+    if num_papers:
+        errors.append(f'Patří mu řešení/opravy ({num_papers})')
+
+    num_uploads = sess.query(db.Paper).filter_by(uploaded_by_obj=user).count()
+    if num_uploads:
+        errors.append(f'Nahrál řešení/opravy ({num_uploads})')
+
+    logs = sess.query(db.Log).filter_by(user=user).all()
+    num_good_logs = 0
+    num_bad_logs = 0
+    for log in logs:
+        if log.details.get('reason', "") == 'user-join':
+            num_good_logs += 1
+        else:
+            num_bad_logs += 1
+    if num_good_logs > 0:
+        warnings.append(f'Vlastní záznamy v logu z registrace ({num_good_logs})')
+    if num_bad_logs > 0:
+        errors.append(f'Vlastní záznamy v logu ({num_bad_logs})')
+
+    form = ConfirmDeleteForm()
+    if form.validate_on_submit() and not errors:
+        sess.rollback()
+
+        conn = sess.connection()
+        pant_table = db.Participation.__table__
+        pion_table = db.Participant.__table__
+        role_table = db.UserRole.__table__
+        log_table = db.Log.__table__
+        conn.execute(pant_table.delete().where(pant_table.c.user_id == user.user_id))
+        conn.execute(pion_table.delete().where(pion_table.c.user_id == user.user_id))
+        conn.execute(role_table.delete().where(role_table.c.user_id == user.user_id))
+        conn.execute(log_table.delete().where(log_table.c.changed_by == user.user_id))
+        sess.commit()
+
+        mo.util.log(
+            type=db.LogType.user,
+            what=user.user_id,
+            details={'action': 'delete', 'user': db.row2dict(user)},
+        )
+        sess.delete(user)
+        sess.commit()
+
+        app.logger.info(f"Uživatel #{user.user_id} smazán")
+        flash('Uživatel smazán.', 'danger')
+        return redirect(url_for('org_orgs') if user.is_org else url_for('org_users'))
+
+    return render_template('org_user_delete.html', user=user, form=form, warnings=warnings, errors=errors)
diff --git a/mo/web/templates/org_org.html b/mo/web/templates/org_org.html
index f242e2780b03f5d2b731b27f89c91516fd78dfbb..9c3c36f3bb0eeb23efa66dcb84a0459f3a4d0c61 100644
--- a/mo/web/templates/org_org.html
+++ b/mo/web/templates/org_org.html
@@ -31,6 +31,7 @@
 {% endif %}
 {% if g.user.is_admin %}
 	<a class="btn btn-default" href="{{ log_url('user', user.user_id) }}">Historie</a>
+	<a class="btn btn-danger" href="{{ url_for('org_user_delete', user_id=user.user_id) }}">Smazat</a>
 {% endif %}
 {% if can_incarnate %}
 <form action="{{ url_for('incarnate', id=user.user_id) }}" method=POST class='btn-group'>
diff --git a/mo/web/templates/org_user.html b/mo/web/templates/org_user.html
index edf1f7684ee37d97e80886c2064c33a45a2b7c7d..965bcb753c81442df73353810ec62c7eb20654de 100644
--- a/mo/web/templates/org_user.html
+++ b/mo/web/templates/org_user.html
@@ -39,6 +39,7 @@
 {% endif %}
 {% if g.user.is_admin %}
 	<a class="btn btn-default" href="{{ log_url('user', user.user_id) }}">Historie</a>
+	<a class="btn btn-danger" href="{{ url_for('org_user_delete', user_id=user.user_id) }}">Smazat</a>
 {% endif %}
 {% if can_incarnate %}
 <form action="{{ url_for('incarnate', id=user.user_id) }}" method=POST class='btn-group'>
diff --git a/mo/web/templates/org_user_delete.html b/mo/web/templates/org_user_delete.html
new file mode 100644
index 0000000000000000000000000000000000000000..5867867956ff9ac31532a0805fe87143d2083586
--- /dev/null
+++ b/mo/web/templates/org_user_delete.html
@@ -0,0 +1,28 @@
+{% extends "base.html" %}
+{% import "bootstrap/wtf.html" as wtf %}
+{% block title %}Smazat uživatele: {{ user.full_name() }}{% endblock %}
+{% block body %}
+
+{% if warnings %}
+<h3>Varováni</h3>
+<ul>
+	{% for w in warnings %}
+	<li>{{ w }}
+	{% endfor %}
+</ul>
+{% endif %}
+
+{% if errors %}
+<h3>Chyby</h3>
+<ul>
+	{% for e in errors %}
+	<li>{{ e }}
+	{% endfor %}
+</ul>
+{% endif %}
+
+{% if form and not errors %}
+{{ wtf.quick_form(form, form_type='simple', button_map={'delete': 'danger'}) }}
+{% endif %}
+
+{% endblock %}