diff --git a/lib/plausible/auth/user.ex b/lib/plausible/auth/user.ex
index bfb3eafd27e6234bb36c9769953c3c8b6ed5f3fe..3a9021c4212328e59c3bf775a40b1bee17a133a1 100644
--- a/lib/plausible/auth/user.ex
+++ b/lib/plausible/auth/user.ex
@@ -4,6 +4,15 @@ defimpl Bamboo.Formatter, for: Plausible.Auth.User do
   end
 end
 
+defmodule Plausible.Auth.GracePeriod do
+  use Ecto.Schema
+
+  embedded_schema do
+    field :end_date, :date
+    field :allowance_required, :integer
+  end
+end
+
 defmodule Plausible.Auth.User do
   use Ecto.Schema
   import Ecto.Changeset
@@ -17,9 +26,9 @@ defmodule Plausible.Auth.User do
     field :name, :string
     field :last_seen, :naive_datetime
     field :trial_expiry_date, :date
-    field :grace_period_end, :date
     field :theme, :string
     field :email_verified, :boolean
+    embeds_one :grace_period, Plausible.Auth.GracePeriod, on_replace: :update
 
     has_many :site_memberships, Plausible.Site.Membership
     has_many :sites, through: [:site_memberships, :site]
@@ -80,8 +89,17 @@ defmodule Plausible.Auth.User do
     change(user, trial_expiry_date: Timex.today() |> Timex.shift(days: -1))
   end
 
-  def start_grace_period(user) do
-    change(user, grace_period_end: Timex.today() |> Timex.shift(days: 7))
+  def start_grace_period(user, allowance_required) do
+    grace_period = %Plausible.Auth.GracePeriod{
+      end_date: Timex.today() |> Timex.shift(days: 7),
+      allowance_required: allowance_required
+    }
+
+    change(user, grace_period: grace_period)
+  end
+
+  def remove_grace_period(user) do
+    change(user, grace_period: nil)
   end
 
   defp trial_expiry() do
diff --git a/lib/plausible/billing/billing.ex b/lib/plausible/billing/billing.ex
index e292cb06d7dee23b85ccd9beaeae1b4e05bb66e3..bd7854f7913dd63172285e4a834767fb00918a9c 100644
--- a/lib/plausible/billing/billing.ex
+++ b/lib/plausible/billing/billing.ex
@@ -17,20 +17,29 @@ defmodule Plausible.Billing do
 
     changeset = Subscription.changeset(%Subscription{}, format_subscription(params))
 
-    Repo.insert(changeset)
-    |> check_lock_status
-    |> maybe_adjust_api_key_limits
+    Repo.insert(changeset) |> after_subscription_update
   end
 
   def subscription_updated(params) do
     subscription = Repo.get_by!(Subscription, paddle_subscription_id: params["subscription_id"])
     changeset = Subscription.changeset(subscription, format_subscription(params))
 
-    Repo.update(changeset)
+    Repo.update(changeset) |> after_subscription_update
+  end
+
+  defp after_subscription_update({:ok, subscription}) do
+    user =
+      Repo.get(Plausible.Auth.User, subscription.user_id)
+      |> Map.put(:subscription, subscription)
+
+    {:ok, user}
+    |> maybe_remove_grace_period
     |> check_lock_status
     |> maybe_adjust_api_key_limits
   end
 
+  defp after_subscription_update(err), do: err
+
   def subscription_cancelled(params) do
     subscription =
       Repo.get_by(Subscription, paddle_subscription_id: params["subscription_id"])
@@ -114,7 +123,7 @@ defmodule Plausible.Billing do
     subscription_active = subscription_is_active?(user.subscription)
 
     grace_period_ended =
-      user.grace_period_end && Timex.before?(user.grace_period_end, Timex.today())
+      user.grace_period && Timex.before?(user.grace_period.end_date, Timex.today())
 
     cond do
       trial_is_over && !subscription_active -> {true, :no_active_subscription}
@@ -225,31 +234,48 @@ defmodule Plausible.Billing do
   defp present?(nil), do: false
   defp present?(_), do: true
 
-  defp check_lock_status({:ok, subscription}) do
-    user =
-      Repo.get(Plausible.Auth.User, subscription.user_id)
-      |> Map.put(:subscription, subscription)
+  defp maybe_remove_grace_period({:ok, user}) do
+    alias Plausible.Auth.GracePeriod
+
+    case user.grace_period do
+      %GracePeriod{allowance_required: allowance_required} ->
+        new_allowance = Plausible.Billing.Plans.allowance(user.subscription)
+
+        if new_allowance > allowance_required do
+          Plausible.Auth.User.remove_grace_period(user)
+          |> Repo.update()
+        else
+          {:ok, user}
+        end
+
+      _ ->
+        {:ok, user}
+    end
+  end
+
+  defp maybe_remove_grace_period(err), do: err
 
+  defp check_lock_status({:ok, user}) do
     Plausible.Billing.SiteLocker.check_sites_for(user)
-    {:ok, subscription}
+    {:ok, user}
   end
 
   defp check_lock_status(err), do: err
 
-  defp maybe_adjust_api_key_limits({:ok, subscription}) do
+  defp maybe_adjust_api_key_limits({:ok, user}) do
     plan =
       Repo.get_by(Plausible.Billing.EnterprisePlan,
-        user_id: subscription.user_id,
-        paddle_plan_id: subscription.paddle_plan_id
+        user_id: user.id,
+        paddle_plan_id: user.subscription.paddle_plan_id
       )
 
     if plan do
-      user_id = subscription.user_id
+      user_id = user.id
       api_keys = from(key in Plausible.Auth.ApiKey, where: key.user_id == ^user_id)
       Repo.update_all(api_keys, set: [hourly_request_limit: plan.hourly_api_request_limit])
     end
 
-    {:ok, subscription}
+    {:ok, user}
   end
 
   defp maybe_adjust_api_key_limits(err), do: err
diff --git a/lib/workers/check_usage.ex b/lib/workers/check_usage.ex
index 41abcb2b7f6a2e2f6384d5efed1b82957c3d5414..ca0193025f1a1d700c645fa7af92236cace05453 100644
--- a/lib/workers/check_usage.ex
+++ b/lib/workers/check_usage.ex
@@ -96,7 +96,7 @@ defmodule Plausible.Workers.CheckUsage do
           )
 
         Plausible.Mailer.send_email_safe(template)
-        Plausible.Auth.User.start_grace_period(subscriber) |> Repo.update()
+        Plausible.Auth.User.start_grace_period(subscriber, last_cycle_usage) |> Repo.update()
 
       _ ->
         nil
diff --git a/priv/repo/migrations/20211028122202_grace_period_end.exs b/priv/repo/migrations/20211028122202_grace_period_end.exs
index c0b6a64cadb15a97e29b8337b7eb5ce3881cedba..e86400b0de2c0e25a4e4df65fbcee78580870834 100644
--- a/priv/repo/migrations/20211028122202_grace_period_end.exs
+++ b/priv/repo/migrations/20211028122202_grace_period_end.exs
@@ -3,7 +3,7 @@ defmodule Plausible.Repo.Migrations.GracePeriodEnd do
 
   def change do
     alter table(:users) do
-      add :grace_period_end, :date
+      add :grace_period, :map
     end
   end
 end
diff --git a/test/plausible/billing/billing_test.exs b/test/plausible/billing/billing_test.exs
index 998addde507218a163a270092a9bfbc224c96bb2..8e5499f56b18984e7d7963666c8630c8ddd903db 100644
--- a/test/plausible/billing/billing_test.exs
+++ b/test/plausible/billing/billing_test.exs
@@ -229,7 +229,8 @@ defmodule Plausible.BillingTest do
   end
 
   @subscription_id "subscription-123"
-  @plan_id "plan-123"
+  @plan_id_10k "654177"
+  @plan_id_100k "654178"
 
   describe "subscription_created" do
     test "creates a subscription" do
@@ -238,7 +239,7 @@ defmodule Plausible.BillingTest do
       Billing.subscription_created(%{
         "alert_name" => "subscription_created",
         "subscription_id" => @subscription_id,
-        "subscription_plan_id" => @plan_id,
+        "subscription_plan_id" => @plan_id_10k,
         "update_url" => "update_url.com",
         "cancel_url" => "cancel_url.com",
         "passthrough" => user.id,
@@ -263,7 +264,7 @@ defmodule Plausible.BillingTest do
         "email" => user.email,
         "alert_name" => "subscription_created",
         "subscription_id" => @subscription_id,
-        "subscription_plan_id" => @plan_id,
+        "subscription_plan_id" => @plan_id_10k,
         "update_url" => "update_url.com",
         "cancel_url" => "cancel_url.com",
         "status" => "active",
@@ -285,7 +286,7 @@ defmodule Plausible.BillingTest do
       Billing.subscription_created(%{
         "alert_name" => "subscription_created",
         "subscription_id" => @subscription_id,
-        "subscription_plan_id" => @plan_id,
+        "subscription_plan_id" => @plan_id_10k,
         "update_url" => "update_url.com",
         "cancel_url" => "cancel_url.com",
         "passthrough" => user.id,
@@ -304,7 +305,7 @@ defmodule Plausible.BillingTest do
       plan =
         insert(:enterprise_plan,
           user: user,
-          paddle_plan_id: @plan_id,
+          paddle_plan_id: @plan_id_10k,
           hourly_api_request_limit: 10_000
         )
 
@@ -313,7 +314,7 @@ defmodule Plausible.BillingTest do
       Billing.subscription_created(%{
         "alert_name" => "subscription_created",
         "subscription_id" => @subscription_id,
-        "subscription_plan_id" => @plan_id,
+        "subscription_plan_id" => @plan_id_10k,
         "update_url" => "update_url.com",
         "cancel_url" => "cancel_url.com",
         "passthrough" => user.id,
@@ -401,6 +402,66 @@ defmodule Plausible.BillingTest do
 
       assert Repo.reload!(api_key).hourly_request_limit == plan.hourly_api_request_limit
     end
+
+    test "if user's grace period has ended, upgrading to the proper plan will unlock sites and remove grace period" do
+      user =
+        insert(:user,
+          grace_period: %Plausible.Auth.GracePeriod{
+            end_date: Timex.shift(Timex.today(), days: -1),
+            allowance_required: 11_000
+          }
+        )
+
+      subscription = insert(:subscription, user: user)
+      site = insert(:site, locked: true, members: [user])
+
+      Billing.subscription_updated(%{
+        "alert_name" => "subscription_updated",
+        "subscription_id" => subscription.paddle_subscription_id,
+        "subscription_plan_id" => @plan_id_100k,
+        "update_url" => "update_url.com",
+        "cancel_url" => "cancel_url.com",
+        "passthrough" => user.id,
+        "old_status" => "past_due",
+        "status" => "active",
+        "next_bill_date" => "2019-06-01",
+        "new_unit_price" => "12.00",
+        "currency" => "EUR"
+      })
+
+      assert Repo.reload!(site).locked == false
+      assert Repo.reload!(user).grace_period == nil
+    end
+
+    test "does not remove grace period if upgraded plan allowance is too low" do
+      user =
+        insert(:user,
+          grace_period: %Plausible.Auth.GracePeriod{
+            end_date: Timex.shift(Timex.today(), days: -1),
+            allowance_required: 11_000
+          }
+        )
+
+      subscription = insert(:subscription, user: user)
+      site = insert(:site, locked: true, members: [user])
+
+      Billing.subscription_updated(%{
+        "alert_name" => "subscription_updated",
+        "subscription_id" => subscription.paddle_subscription_id,
+        "subscription_plan_id" => @plan_id_10k,
+        "update_url" => "update_url.com",
+        "cancel_url" => "cancel_url.com",
+        "passthrough" => user.id,
+        "old_status" => "past_due",
+        "status" => "active",
+        "next_bill_date" => "2019-06-01",
+        "new_unit_price" => "12.00",
+        "currency" => "EUR"
+      })
+
+      assert Repo.reload!(site).locked == true
+      assert Repo.reload!(user).grace_period.allowance_required == 11_000
+    end
   end
 
   describe "subscription_cancelled" do
diff --git a/test/plausible/billing/site_locker_test.exs b/test/plausible/billing/site_locker_test.exs
index e42a2e0d4a893e334cdbfb7b9515f7ec66d2b1c4..8b92304f9e36db1895153f3380e6f8792ece2e11 100644
--- a/test/plausible/billing/site_locker_test.exs
+++ b/test/plausible/billing/site_locker_test.exs
@@ -50,7 +50,14 @@ defmodule Plausible.Billing.SiteLockerTest do
     end
 
     test "does not lock user who has an active subscription and is on grace period" do
-      user = insert(:user, grace_period_end: Timex.shift(Timex.today(), days: 1))
+      user =
+        insert(:user,
+          grace_period: %Plausible.Auth.GracePeriod{
+            end_date: Timex.shift(Timex.today(), days: 1),
+            allowance_required: 10_000
+          }
+        )
+
       insert(:subscription, status: "active", user: user)
       user = Repo.preload(user, :subscription)
       site = insert(:site, members: [user])
@@ -79,7 +86,14 @@ defmodule Plausible.Billing.SiteLockerTest do
     end
 
     test "locks all sites if user has active subscription but grace period has ended" do
-      user = insert(:user, grace_period_end: Timex.shift(Timex.today(), days: -1))
+      user =
+        insert(:user,
+          grace_period: %Plausible.Auth.GracePeriod{
+            end_date: Timex.shift(Timex.today(), days: -1),
+            allowance_required: 10_000
+          }
+        )
+
       insert(:subscription, status: "active", user: user)
       user = Repo.preload(user, :subscription)
       site = insert(:site, members: [user])
@@ -90,7 +104,14 @@ defmodule Plausible.Billing.SiteLockerTest do
     end
 
     test "sends email if grace period has ended" do
-      user = insert(:user, grace_period_end: Timex.shift(Timex.today(), days: -1))
+      user =
+        insert(:user,
+          grace_period: %Plausible.Auth.GracePeriod{
+            end_date: Timex.shift(Timex.today(), days: -1),
+            allowance_required: 10_000
+          }
+        )
+
       insert(:subscription, status: "active", user: user)
       user = Repo.preload(user, :subscription)
       insert(:site, members: [user])
diff --git a/test/workers/check_usage_test.exs b/test/workers/check_usage_test.exs
index c5458458300f6d69ea3822e4ade5187e9f437b86..3dc6418576d92cc4668addeb3ef6dae27a283422 100644
--- a/test/workers/check_usage_test.exs
+++ b/test/workers/check_usage_test.exs
@@ -24,7 +24,7 @@ defmodule Plausible.Workers.CheckUsageTest do
     CheckUsage.perform(nil)
 
     assert_no_emails_delivered()
-    assert Repo.reload(user).grace_period_end == nil
+    assert Repo.reload(user).grace_period == nil
   end
 
   test "does not send an email if account has been over the limit for one billing month", %{
@@ -46,7 +46,7 @@ defmodule Plausible.Workers.CheckUsageTest do
     CheckUsage.perform(nil, billing_stub)
 
     assert_no_emails_delivered()
-    assert Repo.reload(user).grace_period_end == nil
+    assert Repo.reload(user).grace_period == nil
   end
 
   test "sends an email when an account is over their limit for two consecutive billing months", %{
@@ -72,7 +72,7 @@ defmodule Plausible.Workers.CheckUsageTest do
       subject: "[Action required] You have outgrown your Plausible subscription tier"
     )
 
-    assert Repo.reload(user).grace_period_end == Timex.shift(Timex.today(), days: 7)
+    assert Repo.reload(user).grace_period.end_date == Timex.shift(Timex.today(), days: 7)
   end
 
   describe "enterprise customers" do