diff --git a/.sqlx/query-2ba6f5558e04ca1eb9dee3e9c528271da22595b60016a81d8a18f7c6d30011a4.json b/.sqlx/query-2ba6f5558e04ca1eb9dee3e9c528271da22595b60016a81d8a18f7c6d30011a4.json
new file mode 100644
index 0000000..d3b8ebd
--- /dev/null
+++ b/.sqlx/query-2ba6f5558e04ca1eb9dee3e9c528271da22595b60016a81d8a18f7c6d30011a4.json
@@ -0,0 +1,15 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "\n        update lists\n        set title = $1\n        where id = $2",
+  "describe": {
+    "columns": [],
+    "parameters": {
+      "Left": [
+        "Text",
+        "Uuid"
+      ]
+    },
+    "nullable": []
+  },
+  "hash": "2ba6f5558e04ca1eb9dee3e9c528271da22595b60016a81d8a18f7c6d30011a4"
+}
diff --git a/src/db/lists.rs b/src/db/lists.rs
index 4e9ef3c..86b566e 100644
--- a/src/db/lists.rs
+++ b/src/db/lists.rs
@@ -1,4 +1,5 @@
 use serde::Deserialize;
+use sqlx::query;
 use sqlx::query_as;
 use sqlx::FromRow;
 use time::OffsetDateTime;
@@ -69,6 +70,20 @@ pub async fn insert(
 
     Ok(list)
 }
+pub async fn edit_title(tx: &mut AppTx, list_id: Uuid, new_title: String) -> ResponseResult<()> {
+    query!(
+        r#"
+        update lists
+        set title = $1
+        where id = $2"#,
+        new_title,
+        list_id,
+    )
+    .execute(&mut **tx)
+    .await?;
+
+    Ok(())
+}
 
 pub async fn by_id(tx: &mut AppTx, list_id: Uuid) -> ResponseResult<List> {
     let list = query_as!(
diff --git a/src/forms/lists.rs b/src/forms/lists.rs
index fd9d6ec..7d6b831 100644
--- a/src/forms/lists.rs
+++ b/src/forms/lists.rs
@@ -12,6 +12,11 @@ pub struct CreateList {
     pub private: bool,
 }
 
+#[derive(Deserialize, Default)]
+pub struct EditTitle {
+    pub title: String,
+}
+
 #[derive(Deserialize)]
 pub struct EditListPrivate {
     pub private: bool,
diff --git a/src/routes/lists.rs b/src/routes/lists.rs
index 9945ee5..0aca477 100644
--- a/src/routes/lists.rs
+++ b/src/routes/lists.rs
@@ -2,13 +2,13 @@ use crate::form_errors::FormErrors;
 use crate::forms::lists::{CreateList, EditListPinned, EditListPrivate};
 use crate::response_error::ResponseError;
 use crate::server::AppState;
-use crate::views::lists::{CreateListTemplate, UnpinnedListsTemplate};
+use crate::views::lists::{CreateListTemplate, EditListTitleTemplate, UnpinnedListsTemplate};
 use crate::{authentication::AuthUser, response_error::ResponseResult};
 use crate::{
     db::{self},
     views::{layout, lists::ListTemplate},
 };
-use crate::{extract, views};
+use crate::{extract, forms, views};
 use askama_axum::IntoResponse;
 use axum::extract::Path;
 use axum::response::Redirect;
@@ -25,6 +25,8 @@ pub fn router() -> Router<AppState> {
         .route("/lists/create", get(get_create).post(post_create))
         .route("/lists/:list_id", get(list))
         .route("/lists/:list_id/edit_private", post(edit_private))
+        .route("/lists/:list_id/edit_title", post(post_edit_title))
+        .route("/lists/:list_id/edit_title", get(get_edit_title))
         .route("/lists/:list_id/edit_pinned", post(edit_pinned))
         .route("/lists/unpinned", get(list_unpinned))
 }
@@ -96,6 +98,46 @@ async fn get_create(
     })
 }
 
+async fn get_edit_title(
+    extract::Tx(mut tx): extract::Tx,
+    auth_user: AuthUser,
+    Path(list_id): Path<Uuid>,
+) -> ResponseResult<EditListTitleTemplate> {
+    let list = db::lists::by_id(&mut tx, list_id).await?;
+
+    if list.user_id != auth_user.user_id {
+        return Err(ResponseError::NotFound);
+    }
+
+    let layout = layout::Template::from_db(&mut tx, Some(&auth_user)).await?;
+
+    Ok(EditListTitleTemplate {
+        layout,
+        errors: FormErrors::default(),
+        input: forms::lists::EditTitle::default(),
+        list_id,
+    })
+}
+
+async fn post_edit_title(
+    auth_user: AuthUser,
+    extract::Tx(mut tx): extract::Tx,
+    Path(list_id): Path<Uuid>,
+    Form(input): Form<forms::lists::EditTitle>,
+) -> ResponseResult<Response> {
+    let list = db::lists::by_id(&mut tx, list_id).await?;
+
+    if list.user_id != auth_user.user_id {
+        return Err(ResponseError::NotFound);
+    }
+
+    db::lists::edit_title(&mut tx, list_id, input.title).await?;
+
+    tx.commit().await?;
+
+    Ok(Redirect::to(&list.path()).into_response())
+}
+
 async fn edit_private(
     auth_user: AuthUser,
     extract::Tx(mut tx): extract::Tx,
diff --git a/src/views/lists.rs b/src/views/lists.rs
index 39ff38f..accd705 100644
--- a/src/views/lists.rs
+++ b/src/views/lists.rs
@@ -1,9 +1,10 @@
 use askama::Template;
+use uuid::Uuid;
 
 use crate::{
     db::{self},
     form_errors::FormErrors,
-    forms::lists::CreateList,
+    forms::{self, lists::CreateList},
 };
 
 use super::layout;
@@ -25,6 +26,15 @@ pub struct CreateListTemplate {
     pub errors: FormErrors,
 }
 
+#[derive(Template)]
+#[template(path = "edit_list_title.html")]
+pub struct EditListTitleTemplate {
+    pub layout: layout::Template,
+    pub input: forms::lists::EditTitle,
+    pub errors: FormErrors,
+    pub list_id: Uuid,
+}
+
 #[derive(Template)]
 #[template(path = "list_unpinned_lists.html")]
 pub struct UnpinnedListsTemplate {
diff --git a/templates/edit_list_title.html b/templates/edit_list_title.html
new file mode 100644
index 0000000..86b73b9
--- /dev/null
+++ b/templates/edit_list_title.html
@@ -0,0 +1,33 @@
+{% import "_form.html" as form %}
+{% extends "_layout.html" %}
+
+{% block content %}
+  <form
+    action="/lists/{{ list_id }}/edit_title"
+    method="POST"
+    class="flex flex-col max-w-xl mx-4 mb-4 grow"
+  >
+    <header class="mt-3 mb-4">
+      <h1 class="text-xl font-bold">Rename list</h1>
+    </header>
+
+    <label for="title">New title</label>
+    {% call form::errors(errors, "title") %}
+    <input
+      type="text"
+      name="title"
+      required
+      value="{{ input.title }}"
+      class="rounded py-1.5 px-3 mt-2 bg-neutral-900"
+    />
+
+    {% call form::errors(errors, "root") %}
+
+    <button
+      type="submit"
+      class="bg-neutral-300 py-1.5 px-3 text-neutral-900 rounded mt-4 self-end"
+    >
+      Save Changes
+    </button>
+  </form>
+{% endblock %}
diff --git a/templates/list.html b/templates/list.html
index c44adc0..1903904 100644
--- a/templates/list.html
+++ b/templates/list.html
@@ -69,6 +69,11 @@ <h1 class="text-xl font-bold">{{ list.title }}</h1>
             {% endif %}
           </button>
         </form>
+        <a
+          href="/lists/{{ list.id }}/edit_title"
+          class="block px-4 py-1 border rounded hover:bg-neutral-700 border-neutral-700 w-max"
+          >Rename</a
+        >
         <a
           href="/bookmarks/create?parent_id={{ list.id }}"
           class="block px-4 py-1 border rounded hover:bg-neutral-700 border-neutral-700 w-max"