diff --git a/lib/alchemy/upgrader/five_point_zero.rb b/lib/alchemy/upgrader/five_point_zero.rb
new file mode 100644
index 0000000000..9cbaff7c13
--- /dev/null
+++ b/lib/alchemy/upgrader/five_point_zero.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require_relative 'tasks/harden_gutentag_migrations'
+
+module Alchemy
+  class Upgrader::FivePointZero < Upgrader
+    class << self
+      def install_gutentag_migrations
+        desc 'Install Gutentag migrations'
+        `bundle exec rake gutentag:install:migrations`
+        Alchemy::Upgrader::Tasks::HardenGutentagMigrations.new.patch_migrations
+        `bundle exec rake db:migrate`
+      end
+    end
+  end
+end
diff --git a/lib/alchemy/upgrader/tasks/harden_gutentag_migrations.rb b/lib/alchemy/upgrader/tasks/harden_gutentag_migrations.rb
new file mode 100644
index 0000000000..53e8b9abd8
--- /dev/null
+++ b/lib/alchemy/upgrader/tasks/harden_gutentag_migrations.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'thor'
+
+module Alchemy::Upgrader::Tasks
+  class HardenGutentagMigrations < Thor
+    include Thor::Actions
+
+    no_tasks do
+      def patch_migrations
+        sentinel = /def up/
+
+        migration_file = Dir.glob('db/migrate/*_gutentag_tables.gutentag.rb').first
+        if migration_file
+          inject_into_file migration_file,
+            "\n    # inserted by Alchemy CMS upgrader\n    return if table_exists?(:gutentag_taggings)\n",
+            { after: sentinel, verbose: true }
+        end
+
+        migration_file = Dir.glob('db/migrate/*_gutentag_cache_counter.gutentag.rb').first
+        if migration_file
+          inject_into_file migration_file,
+            "\n    # inserted by Alchemy CMS upgrader\n    return if column_exists?(:gutentag_tags, :taggings_count)\n",
+            { after: sentinel, verbose: true }
+        end
+      end
+    end
+  end
+end
diff --git a/lib/rails/generators/alchemy/install/install_generator.rb b/lib/rails/generators/alchemy/install/install_generator.rb
index 84f0716652..be4ac7efc1 100644
--- a/lib/rails/generators/alchemy/install/install_generator.rb
+++ b/lib/rails/generators/alchemy/install/install_generator.rb
@@ -53,6 +53,10 @@ def copy_dragonfly_config
         template "#{__dir__}/templates/dragonfly.rb.tt", "config/initializers/dragonfly.rb"
       end
 
+      def install_gutentag_migrations
+        rake 'gutentag:install:migrations'
+      end
+
       private
 
       def config_path
diff --git a/lib/tasks/alchemy/upgrade.rake b/lib/tasks/alchemy/upgrade.rake
index 528d2e7b2b..59bbd42941 100644
--- a/lib/tasks/alchemy/upgrade.rake
+++ b/lib/tasks/alchemy/upgrade.rake
@@ -18,6 +18,7 @@ namespace :alchemy do
 
     desc "Alchemy Upgrader: Prepares the database."
     task database: [
+      'alchemy:upgrade:5.0:install_gutentag_migrations',
       'alchemy:install:migrations',
       'db:migrate',
       'alchemy:db:seed'
@@ -27,5 +28,19 @@ namespace :alchemy do
     task config: [:environment] do
       Alchemy::Upgrader.copy_new_config_file
     end
+
+    desc 'Upgrade Alchemy to v5.0'
+    task '5.0' => [
+      'alchemy:upgrade:prepare'
+    ] do
+      Alchemy::Upgrader.display_todos
+    end
+
+    namespace '5.0' do
+      desc 'Install Gutentag migrations'
+      task install_gutentag_migrations: [:environment] do
+        Alchemy::Upgrader::FivePointZero.install_gutentag_migrations
+      end
+    end
   end
 end
diff --git a/spec/dummy/db/migrate/20191129235819_gutentag_tables.gutentag.rb b/spec/dummy/db/migrate/20191129235819_gutentag_tables.gutentag.rb
new file mode 100644
index 0000000000..4dbea15c75
--- /dev/null
+++ b/spec/dummy/db/migrate/20191129235819_gutentag_tables.gutentag.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+# This migration comes from gutentag (originally 1)
+
+superclass = ActiveRecord::VERSION::MAJOR < 5 ?
+  ActiveRecord::Migration : ActiveRecord::Migration[4.2]
+class GutentagTables < superclass
+  def up
+    # inserted by Alchemy CMS upgrader
+    return if table_exists?(:gutentag_taggings)
+
+    create_table :gutentag_taggings do |t|
+      t.integer :tag_id,        :null => false
+      t.integer :taggable_id,   :null => false
+      t.string  :taggable_type, :null => false
+      t.timestamps :null => false
+    end
+
+    add_index :gutentag_taggings, :tag_id
+    add_index :gutentag_taggings, %i[ taggable_type taggable_id ]
+    add_index :gutentag_taggings, %i[ taggable_type taggable_id tag_id ],
+      :unique => true, :name => "unique_taggings"
+
+    create_table :gutentag_tags do |t|
+      t.string :name, :null => false
+      t.timestamps :null => false
+    end
+
+    add_index :gutentag_tags, :name, :unique => true
+  end
+
+  def down
+    drop_table :gutentag_tags
+    drop_table :gutentag_taggings
+  end
+end
diff --git a/spec/dummy/db/migrate/20191129235820_gutentag_cache_counter.gutentag.rb b/spec/dummy/db/migrate/20191129235820_gutentag_cache_counter.gutentag.rb
new file mode 100644
index 0000000000..cc093b257f
--- /dev/null
+++ b/spec/dummy/db/migrate/20191129235820_gutentag_cache_counter.gutentag.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+# This migration comes from gutentag (originally 2)
+
+superclass = ActiveRecord::VERSION::MAJOR < 5 ?
+  ActiveRecord::Migration : ActiveRecord::Migration[4.2]
+class GutentagCacheCounter < superclass
+  def up
+    # inserted by Alchemy CMS upgrader
+    return if column_exists?(:gutentag_tags, :taggings_count)
+
+    add_column :gutentag_tags, :taggings_count, :integer, :default => 0
+    add_index  :gutentag_tags, :taggings_count
+
+    Gutentag::Tag.reset_column_information
+    Gutentag::Tag.pluck(:id).each do |tag_id|
+      Gutentag::Tag.reset_counters tag_id, :taggings
+    end
+  end
+
+  def down
+    remove_column :gutentag_tags, :taggings_count
+  end
+end
diff --git a/spec/dummy/db/migrate/20191129235821_no_null_counters.gutentag.rb b/spec/dummy/db/migrate/20191129235821_no_null_counters.gutentag.rb
new file mode 100644
index 0000000000..8503167f75
--- /dev/null
+++ b/spec/dummy/db/migrate/20191129235821_no_null_counters.gutentag.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+# This migration comes from gutentag (originally 3)
+
+superclass = ActiveRecord::VERSION::MAJOR < 5 ?
+  ActiveRecord::Migration : ActiveRecord::Migration[4.2]
+class NoNullCounters < superclass
+  def up
+    change_column :gutentag_tags, :taggings_count, :integer,
+      :default => 0,
+      :null    => false
+  end
+
+  def down
+    change_column :gutentag_tags, :taggings_count, :integer,
+      :default => 0,
+      :null    => true
+  end
+end
diff --git a/spec/dummy/db/schema.rb b/spec/dummy/db/schema.rb
index 14cf121075..d03a022441 100644
--- a/spec/dummy/db/schema.rb
+++ b/spec/dummy/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2019_10_29_212236) do
+ActiveRecord::Schema.define(version: 2019_11_29_235821) do
 
   create_table "alchemy_attachments", force: :cascade do |t|
     t.string "name"
@@ -339,7 +339,7 @@
 
   create_table "gutentag_tags", force: :cascade do |t|
     t.string "name", null: false
-    t.integer "taggings_count", default: 0
+    t.integer "taggings_count", default: 0, null: false
     t.index ["name"], name: "index_gutentag_tags_on_name", unique: true
     t.index ["taggings_count"], name: "index_gutentag_tags_on_taggings_count"
   end