diff --git a/Makefile b/Makefile
index a39484620..3e992f15e 100644
--- a/Makefile
+++ b/Makefile
@@ -469,7 +469,7 @@ test-mssql\#%: integrations.mssql.test generate-ini-mssql
 
 .PHONY: test-mssql-migration
 test-mssql-migration: migrations.mssql.test generate-ini-mssql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mssql.ini ./migrations.mssql.test
+	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mssql.ini ./migrations.mssql.test -test.failfast
 
 .PHONY: bench-sqlite
 bench-sqlite: integrations.sqlite.test generate-ini-sqlite
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 565e58315..5317cc574 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -235,6 +235,8 @@ var migrations = []Migration{
 	NewMigration("Add Created and Updated to Milestone table", addCreatedAndUpdatedToMilestones),
 	// v150 -> v151
 	NewMigration("add primary key to repo_topic", addPrimaryKeyToRepoTopic),
+	// v151 -> v152
+	NewMigration("set default password algorithm to Argon2", setDefaultPasswordToArgon2),
 }
 
 // GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v151.go b/models/migrations/v151.go
new file mode 100644
index 000000000..ba6eee344
--- /dev/null
+++ b/models/migrations/v151.go
@@ -0,0 +1,194 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package migrations
+
+import (
+	"fmt"
+	"strings"
+
+	"code.gitea.io/gitea/modules/log"
+	"code.gitea.io/gitea/modules/setting"
+
+	"xorm.io/xorm"
+	"xorm.io/xorm/schemas"
+)
+
+func setDefaultPasswordToArgon2(x *xorm.Engine) error {
+	switch {
+	case setting.Database.UseMySQL:
+		_, err := x.Exec("ALTER TABLE `user` ALTER passwd_hash_algo SET DEFAULT 'argon2';")
+		return err
+	case setting.Database.UsePostgreSQL:
+		_, err := x.Exec("ALTER TABLE `user` ALTER COLUMN passwd_hash_algo SET DEFAULT 'argon2';")
+		return err
+	case setting.Database.UseMSSQL:
+		// need to find the constraint and drop it, then recreate it.
+		sess := x.NewSession()
+		defer sess.Close()
+		if err := sess.Begin(); err != nil {
+			return err
+		}
+		res, err := sess.QueryString("SELECT [name] FROM sys.default_constraints WHERE parent_object_id=OBJECT_ID(?) AND COL_NAME(parent_object_id, parent_column_id)=?;", "user", "passwd_hash_algo")
+		if err != nil {
+			return err
+		}
+		if len(res) > 0 {
+			constraintName := res[0]["name"]
+			log.Error("Results of select constraint: %s", constraintName)
+			_, err := sess.Exec("ALTER TABLE [user] DROP CONSTRAINT " + constraintName)
+			if err != nil {
+				return err
+			}
+			_, err = sess.Exec("ALTER TABLE [user] ADD CONSTRAINT " + constraintName + " DEFAULT 'argon2' FOR passwd_hash_algo")
+			if err != nil {
+				return err
+			}
+		} else {
+			_, err := sess.Exec("ALTER TABLE [user] ADD DEFAULT('argon2') FOR passwd_hash_algo")
+			if err != nil {
+				return err
+			}
+		}
+		return sess.Commit()
+
+	case setting.Database.UseSQLite3:
+		// drop through
+	default:
+		log.Fatal("Unrecognized DB")
+	}
+
+	tables, err := x.DBMetas()
+	if err != nil {
+		return err
+	}
+
+	// Now for SQLite we have to recreate the table
+	var table *schemas.Table
+	tableName := "user"
+
+	for _, table = range tables {
+		if table.Name == tableName {
+			break
+		}
+	}
+	if table == nil || table.Name != tableName {
+		type User struct {
+			PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'argon2'"`
+		}
+		return x.Sync2(new(User))
+	}
+	column := table.GetColumn("passwd_hash_algo")
+	if column == nil {
+		type User struct {
+			PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'argon2'"`
+		}
+		return x.Sync2(new(User))
+	}
+	sess := x.NewSession()
+	defer sess.Close()
+	if err := sess.Begin(); err != nil {
+		return err
+	}
+
+	tempTableName := "tmp_recreate__user"
+	column.Default = "'argon2'"
+
+	createTableSQL, _ := x.Dialect().CreateTableSQL(table, tempTableName)
+	for _, sql := range createTableSQL {
+		if _, err := sess.Exec(sql); err != nil {
+			log.Error("Unable to create table %s. Error: %v\n", tempTableName, err, createTableSQL)
+			return err
+		}
+	}
+	for _, index := range table.Indexes {
+		if _, err := sess.Exec(x.Dialect().CreateIndexSQL(tempTableName, index)); err != nil {
+			log.Error("Unable to create indexes on temporary table %s. Error: %v", tempTableName, err)
+			return err
+		}
+	}
+
+	newTableColumns := table.Columns()
+	if len(newTableColumns) == 0 {
+		return fmt.Errorf("no columns in new table")
+	}
+	hasID := false
+	for _, column := range newTableColumns {
+		hasID = hasID || (column.IsPrimaryKey && column.IsAutoIncrement)
+	}
+
+	sqlStringBuilder := &strings.Builder{}
+	_, _ = sqlStringBuilder.WriteString("INSERT INTO `")
+	_, _ = sqlStringBuilder.WriteString(tempTableName)
+	_, _ = sqlStringBuilder.WriteString("` (`")
+	_, _ = sqlStringBuilder.WriteString(newTableColumns[0].Name)
+	_, _ = sqlStringBuilder.WriteString("`")
+	for _, column := range newTableColumns[1:] {
+		_, _ = sqlStringBuilder.WriteString(", `")
+		_, _ = sqlStringBuilder.WriteString(column.Name)
+		_, _ = sqlStringBuilder.WriteString("`")
+	}
+	_, _ = sqlStringBuilder.WriteString(")")
+	_, _ = sqlStringBuilder.WriteString(" SELECT ")
+	if newTableColumns[0].Default != "" {
+		_, _ = sqlStringBuilder.WriteString("COALESCE(`")
+		_, _ = sqlStringBuilder.WriteString(newTableColumns[0].Name)
+		_, _ = sqlStringBuilder.WriteString("`, ")
+		_, _ = sqlStringBuilder.WriteString(newTableColumns[0].Default)
+		_, _ = sqlStringBuilder.WriteString(")")
+	} else {
+		_, _ = sqlStringBuilder.WriteString("`")
+		_, _ = sqlStringBuilder.WriteString(newTableColumns[0].Name)
+		_, _ = sqlStringBuilder.WriteString("`")
+	}
+
+	for _, column := range newTableColumns[1:] {
+		if column.Default != "" {
+			_, _ = sqlStringBuilder.WriteString(", COALESCE(`")
+			_, _ = sqlStringBuilder.WriteString(column.Name)
+			_, _ = sqlStringBuilder.WriteString("`, ")
+			_, _ = sqlStringBuilder.WriteString(column.Default)
+			_, _ = sqlStringBuilder.WriteString(")")
+		} else {
+			_, _ = sqlStringBuilder.WriteString(", `")
+			_, _ = sqlStringBuilder.WriteString(column.Name)
+			_, _ = sqlStringBuilder.WriteString("`")
+		}
+	}
+	_, _ = sqlStringBuilder.WriteString(" FROM `")
+	_, _ = sqlStringBuilder.WriteString(tableName)
+	_, _ = sqlStringBuilder.WriteString("`")
+
+	if _, err := sess.Exec(sqlStringBuilder.String()); err != nil {
+		log.Error("Unable to set copy data in to temp table %s. Error: %v", tempTableName, err)
+		return err
+	}
+
+	// SQLite will drop all the constraints on the old table
+	if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil {
+		log.Error("Unable to drop old table %s. Error: %v", tableName, err)
+		return err
+	}
+
+	for _, index := range table.Indexes {
+		if _, err := sess.Exec(x.Dialect().DropIndexSQL(tempTableName, index)); err != nil {
+			log.Error("Unable to drop indexes on temporary table %s. Error: %v", tempTableName, err)
+			return err
+		}
+	}
+
+	if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` RENAME TO `%s`", tempTableName, tableName)); err != nil {
+		log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
+		return err
+	}
+
+	for _, index := range table.Indexes {
+		if _, err := sess.Exec(x.Dialect().CreateIndexSQL(tableName, index)); err != nil {
+			log.Error("Unable to recreate indexes on table %s. Error: %v", tableName, err)
+			return err
+		}
+	}
+
+	return sess.Commit()
+}