diff --git a/backend/app/api/v1/entry.go b/backend/app/api/v1/entry.go
index 0683a8446..ca02b8a9c 100644
--- a/backend/app/api/v1/entry.go
+++ b/backend/app/api/v1/entry.go
@@ -21,8 +21,9 @@ var (
 	imageService           = service.NewIImageService()
 	dockerService          = service.NewIDockerService()
 
-	mysqlService = service.NewIMysqlService()
-	redisService = service.NewIRedisService()
+	mysqlService    = service.NewIMysqlService()
+	remoteDBService = service.NewIRemoteDBService()
+	redisService    = service.NewIRedisService()
 
 	cronjobService = service.NewICronjobService()
 
diff --git a/backend/app/api/v1/remote_db.go b/backend/app/api/v1/remote_db.go
new file mode 100644
index 000000000..413a5a8e6
--- /dev/null
+++ b/backend/app/api/v1/remote_db.go
@@ -0,0 +1,133 @@
+package v1
+
+import (
+	"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
+	"github.com/1Panel-dev/1Panel/backend/app/dto"
+	"github.com/1Panel-dev/1Panel/backend/constant"
+	"github.com/1Panel-dev/1Panel/backend/global"
+	"github.com/gin-gonic/gin"
+)
+
+// @Tags Database
+// @Summary Create remote database
+// @Description 创建远程数据库
+// @Accept json
+// @Param request body dto.DatabaseCreate true "request"
+// @Success 200
+// @Security ApiKeyAuth
+// @Router /databases/remote [post]
+// @x-panel-log {"bodyKeys":["name", "type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建远程数据库 [name][type]","formatEN":"create remote database [name][type]"}
+func (b *BaseApi) CreateRemoteDB(c *gin.Context) {
+	var req dto.RemoteDBCreate
+	if err := c.ShouldBindJSON(&req); err != nil {
+		helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
+		return
+	}
+	if err := global.VALID.Struct(req); err != nil {
+		helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
+		return
+	}
+	if err := remoteDBService.Create(req); err != nil {
+		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
+		return
+	}
+	helper.SuccessWithData(c, nil)
+}
+
+// @Tags Database
+// @Summary Page remote databases
+// @Description 获取远程数据库列表分页
+// @Accept json
+// @Param request body dto.SearchWithPage true "request"
+// @Success 200 {object} dto.PageResult
+// @Security ApiKeyAuth
+// @Router /databases/remote/search [post]
+func (b *BaseApi) SearchRemoteDB(c *gin.Context) {
+	var req dto.RemoteDBSearch
+	if err := c.ShouldBindJSON(&req); err != nil {
+		helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
+		return
+	}
+
+	total, list, err := remoteDBService.SearchWithPage(req)
+	if err != nil {
+		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
+		return
+	}
+
+	helper.SuccessWithData(c, dto.PageResult{
+		Items: list,
+		Total: total,
+	})
+}
+
+// @Tags Database
+// @Summary List remote databases
+// @Description 获取快速命令列表
+// @Success 200 {array} dto.RemoteDBOption
+// @Security ApiKeyAuth
+// @Router /databases/remote/list/:type [get]
+func (b *BaseApi) ListRemoteDB(c *gin.Context) {
+	dbType := c.Query("type")
+	list, err := remoteDBService.List(dbType)
+	if err != nil {
+		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
+		return
+	}
+
+	helper.SuccessWithData(c, list)
+}
+
+// @Tags Database
+// @Summary Delete remote database
+// @Description 删除远程数据库
+// @Accept json
+// @Param request body dto.OperateByID true "request"
+// @Success 200
+// @Security ApiKeyAuth
+// @Router /databases/remote/del [post]
+// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"databases","output_column":"name","output_value":"names"}],"formatZH":"删除远程数据库 [names]","formatEN":"delete remote database [names]"}
+func (b *BaseApi) DeleteRemoteDB(c *gin.Context) {
+	var req dto.OperateByID
+	if err := c.ShouldBindJSON(&req); err != nil {
+		helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
+		return
+	}
+	if err := global.VALID.Struct(req); err != nil {
+		helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
+		return
+	}
+
+	if err := remoteDBService.Delete(req.ID); err != nil {
+		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
+		return
+	}
+	helper.SuccessWithData(c, nil)
+}
+
+// @Tags Database
+// @Summary Update remote database
+// @Description 更新远程数据库
+// @Accept json
+// @Param request body dto.DatabaseUpdate true "request"
+// @Success 200
+// @Security ApiKeyAuth
+// @Router /databases/remote/update [post]
+// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新远程数据库 [name]","formatEN":"update remote database [name]"}
+func (b *BaseApi) UpdateRemoteDB(c *gin.Context) {
+	var req dto.RemoteDBUpdate
+	if err := c.ShouldBindJSON(&req); err != nil {
+		helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
+		return
+	}
+	if err := global.VALID.Struct(req); err != nil {
+		helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
+		return
+	}
+
+	if err := remoteDBService.Update(req); err != nil {
+		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
+		return
+	}
+	helper.SuccessWithData(c, nil)
+}
diff --git a/backend/app/dto/database.go b/backend/app/dto/database.go
index 86bdbdfeb..e204b65d9 100644
--- a/backend/app/dto/database.go
+++ b/backend/app/dto/database.go
@@ -16,6 +16,7 @@ type MysqlDBInfo struct {
 
 type MysqlDBCreate struct {
 	Name        string `json:"name" validate:"required"`
+	From        string `json:"from" validate:"required"`
 	Format      string `json:"format" validate:"required,oneof=utf8mb4 utf8 gbk big5"`
 	Username    string `json:"username" validate:"required"`
 	Password    string `json:"password" validate:"required"`
@@ -100,6 +101,7 @@ type MysqlConfUpdateByFile struct {
 
 type ChangeDBInfo struct {
 	ID    uint   `json:"id"`
+	From  string `json:"from" validate:"required"`
 	Value string `json:"value" validate:"required"`
 }
 
diff --git a/backend/app/dto/remote_db.go b/backend/app/dto/remote_db.go
new file mode 100644
index 000000000..aa859973e
--- /dev/null
+++ b/backend/app/dto/remote_db.go
@@ -0,0 +1,52 @@
+package dto
+
+import "time"
+
+type RemoteDBSearch struct {
+	PageInfo
+	Info    string `json:"info"`
+	Type    string `json:"type"`
+	OrderBy string `json:"orderBy"`
+	Order   string `json:"order"`
+}
+
+type RemoteDBInfo struct {
+	ID          uint      `json:"id"`
+	CreatedAt   time.Time `json:"createdAt"`
+	Name        string    `json:"name"`
+	From        string    `json:"from"`
+	Version     string    `json:"version"`
+	Address     string    `json:"address"`
+	Port        uint      `json:"port"`
+	Username    string    `json:"username"`
+	Password    string    `json:"password"`
+	Description string    `json:"description"`
+}
+
+type RemoteDBOption struct {
+	ID      uint   `json:"id"`
+	Name    string `json:"name"`
+	Address string `json:"address"`
+}
+
+type RemoteDBCreate struct {
+	Name        string `json:"name" validate:"required"`
+	Type        string `json:"type" validate:"required,oneof=mysql"`
+	From        string `json:"from" validate:"required,oneof=local remote"`
+	Version     string `json:"version" validate:"required"`
+	Address     string `json:"address"`
+	Port        uint   `json:"port"`
+	Username    string `json:"username" validate:"required"`
+	Password    string `json:"password" validate:"required"`
+	Description string `json:"description"`
+}
+
+type RemoteDBUpdate struct {
+	ID          uint   `json:"id"`
+	Version     string `json:"version" validate:"required"`
+	Address     string `json:"address"`
+	Port        uint   `json:"port"`
+	Username    string `json:"username" validate:"required"`
+	Password    string `json:"password" validate:"required"`
+	Description string `json:"description"`
+}
diff --git a/backend/app/model/database_mysql.go b/backend/app/model/database_mysql.go
index bc699aac4..9a5137e12 100644
--- a/backend/app/model/database_mysql.go
+++ b/backend/app/model/database_mysql.go
@@ -3,6 +3,7 @@ package model
 type DatabaseMysql struct {
 	BaseModel
 	Name        string `json:"name" gorm:"type:varchar(256);not null"`
+	From        string `json:"type" gorm:"type:varchar(256);not null"`
 	MysqlName   string `json:"mysqlName" gorm:"type:varchar(64);not null"`
 	Format      string `json:"format" gorm:"type:varchar(64);not null"`
 	Username    string `json:"username" gorm:"type:varchar(256);not null"`
diff --git a/backend/app/model/database.go b/backend/app/model/remote_db.go
similarity index 75%
rename from backend/app/model/database.go
rename to backend/app/model/remote_db.go
index 58bd8accb..8e442b37e 100644
--- a/backend/app/model/database.go
+++ b/backend/app/model/remote_db.go
@@ -1,13 +1,14 @@
 package model
 
-type Database struct {
+type RemoteDB struct {
 	BaseModel
 	Name        string `json:"name" gorm:"type:varchar(64);not null"`
 	Type        string `json:"type" gorm:"type:varchar(64);not null"`
+	Version     string `json:"version" gorm:"type:varchar(64);not null"`
+	From        string `json:"from" gorm:"type:varchar(64);not null"`
 	Address     string `json:"address" gorm:"type:varchar(64);not null"`
 	Port        uint   `json:"port" gorm:"type:decimal;not null"`
 	Username    string `json:"username" gorm:"type:varchar(64)"`
 	Password    string `json:"password" gorm:"type:varchar(64)"`
-	Format      string `json:"format" gorm:"type:varchar(64)"`
 	Description string `json:"description" gorm:"type:varchar(256);"`
 }
diff --git a/backend/app/repo/remote_db.go b/backend/app/repo/remote_db.go
new file mode 100644
index 000000000..a49270760
--- /dev/null
+++ b/backend/app/repo/remote_db.go
@@ -0,0 +1,77 @@
+package repo
+
+import (
+	"github.com/1Panel-dev/1Panel/backend/app/model"
+	"github.com/1Panel-dev/1Panel/backend/global"
+	"gorm.io/gorm"
+)
+
+type RemoteDBRepo struct{}
+
+type IRemoteDBRepo interface {
+	GetList(opts ...DBOption) ([]model.RemoteDB, error)
+	Page(limit, offset int, opts ...DBOption) (int64, []model.RemoteDB, error)
+	Create(database *model.RemoteDB) error
+	Update(id uint, vars map[string]interface{}) error
+	Delete(opts ...DBOption) error
+	Get(opts ...DBOption) (model.RemoteDB, error)
+	WithoutByFrom(from string) DBOption
+}
+
+func NewIRemoteDBRepo() IRemoteDBRepo {
+	return &RemoteDBRepo{}
+}
+
+func (u *RemoteDBRepo) Get(opts ...DBOption) (model.RemoteDB, error) {
+	var database model.RemoteDB
+	db := global.DB
+	for _, opt := range opts {
+		db = opt(db)
+	}
+	err := db.First(&database).Error
+	return database, err
+}
+
+func (u *RemoteDBRepo) Page(page, size int, opts ...DBOption) (int64, []model.RemoteDB, error) {
+	var users []model.RemoteDB
+	db := global.DB.Model(&model.RemoteDB{})
+	for _, opt := range opts {
+		db = opt(db)
+	}
+	count := int64(0)
+	db = db.Count(&count)
+	err := db.Limit(size).Offset(size * (page - 1)).Find(&users).Error
+	return count, users, err
+}
+
+func (u *RemoteDBRepo) GetList(opts ...DBOption) ([]model.RemoteDB, error) {
+	var databases []model.RemoteDB
+	db := global.DB.Model(&model.RemoteDB{})
+	for _, opt := range opts {
+		db = opt(db)
+	}
+	err := db.Find(&databases).Error
+	return databases, err
+}
+
+func (c *RemoteDBRepo) WithoutByFrom(from string) DBOption {
+	return func(g *gorm.DB) *gorm.DB {
+		return g.Where("`from` != ?", from)
+	}
+}
+
+func (u *RemoteDBRepo) Create(database *model.RemoteDB) error {
+	return global.DB.Create(database).Error
+}
+
+func (u *RemoteDBRepo) Update(id uint, vars map[string]interface{}) error {
+	return global.DB.Model(&model.RemoteDB{}).Where("id = ?", id).Updates(vars).Error
+}
+
+func (u *RemoteDBRepo) Delete(opts ...DBOption) error {
+	db := global.DB
+	for _, opt := range opts {
+		db = opt(db)
+	}
+	return db.Delete(&model.RemoteDB{}).Error
+}
diff --git a/backend/app/service/database_mysql.go b/backend/app/service/database_mysql.go
index dde139887..89edd3e88 100644
--- a/backend/app/service/database_mysql.go
+++ b/backend/app/service/database_mysql.go
@@ -20,6 +20,8 @@ import (
 	"github.com/1Panel-dev/1Panel/backend/utils/cmd"
 	"github.com/1Panel-dev/1Panel/backend/utils/common"
 	"github.com/1Panel-dev/1Panel/backend/utils/compose"
+	"github.com/1Panel-dev/1Panel/backend/utils/mysql"
+	"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
 	_ "github.com/go-sql-driver/mysql"
 	"github.com/jinzhu/copier"
 	"github.com/pkg/errors"
@@ -70,50 +72,69 @@ func (u *MysqlService) ListDBName() ([]string, error) {
 	return dbNames, err
 }
 
-var formatMap = map[string]string{
-	"utf8":    "utf8_general_ci",
-	"utf8mb4": "utf8mb4_general_ci",
-	"gbk":     "gbk_chinese_ci",
-	"big5":    "big5_chinese_ci",
-}
-
 func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error) {
 	if cmd.CheckIllegal(req.Name, req.Username, req.Password, req.Format, req.Permission) {
 		return nil, buserr.New(constant.ErrCmdIllegal)
 	}
 
-	if req.Username == "root" {
-		return nil, errors.New("Cannot set root as user name")
-	}
-	app, err := appInstallRepo.LoadBaseInfo("mysql", "")
-	if err != nil {
-		return nil, err
-	}
-	mysql, _ := mysqlRepo.Get(commonRepo.WithByName(req.Name))
-	if mysql.ID != 0 {
-		return nil, constant.ErrRecordExist
-	}
-	if err := copier.Copy(&mysql, &req); err != nil {
+	var createItem model.DatabaseMysql
+	if err := copier.Copy(&createItem, &req); err != nil {
 		return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
 	}
 
-	createSql := fmt.Sprintf("create database `%s` default character set %s collate %s", req.Name, req.Format, formatMap[req.Format])
-	if err := excSQL(app.ContainerName, app.Password, createSql); err != nil {
-		if strings.Contains(err.Error(), "ERROR 1007") {
-			return nil, buserr.New(constant.ErrDatabaseIsExist)
+	if req.Username == "root" {
+		return nil, errors.New("Cannot set root as user name")
+	}
+
+	dbInfo := client.DBInfo{
+		From:    req.From,
+		Timeout: 300,
+	}
+	version := ""
+	if req.From == "local" {
+		app, err := appInstallRepo.LoadBaseInfo("mysql", "")
+		if err != nil {
+			return nil, err
 		}
+		mysqlData, _ := mysqlRepo.Get(commonRepo.WithByName(req.Name))
+		if mysqlData.ID != 0 {
+			return nil, constant.ErrRecordExist
+		}
+		dbInfo.Address = app.ContainerName
+		dbInfo.Username = "root"
+		dbInfo.Password = app.Password
+		version = app.Version
+		createItem.MysqlName = app.Name
+	} else {
+		mysqlData, err := remoteDBRepo.Get(commonRepo.WithByName(req.From))
+		if err != nil {
+			return nil, err
+		}
+		dbInfo.Address = mysqlData.Address
+		dbInfo.Port = mysqlData.Port
+		dbInfo.Username = mysqlData.Username
+		dbInfo.Password = mysqlData.Password
+		version = mysqlData.Version
+		createItem.MysqlName = mysqlData.Name
+	}
+
+	cli, err := mysql.NewMysqlClient(dbInfo)
+	if err != nil {
 		return nil, err
 	}
-	if err := u.createUser(app.ContainerName, app.Password, app.Version, req); err != nil {
+	if err := cli.Create(client.CreateInfo{
+		Name:    req.Name,
+		Format:  req.Format,
+		Version: version,
+	}); err != nil {
 		return nil, err
 	}
 
 	global.LOG.Infof("create database %s successful!", req.Name)
-	mysql.MysqlName = app.Name
-	if err := mysqlRepo.Create(ctx, &mysql); err != nil {
+	if err := mysqlRepo.Create(ctx, &createItem); err != nil {
 		return nil, err
 	}
-	return &mysql, nil
+	return &createItem, nil
 }
 
 func (u *MysqlService) UpdateDescription(req dto.UpdateDescription) error {
@@ -143,29 +164,28 @@ func (u *MysqlService) DeleteCheck(id uint) ([]string, error) {
 }
 
 func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error {
-	app, err := appInstallRepo.LoadBaseInfo("mysql", "")
-	if err != nil && !req.ForceDelete {
+	cli, version, err := loadClientByID(req.ID)
+	if err != nil {
 		return err
 	}
-
 	db, err := mysqlRepo.Get(commonRepo.WithByID(req.ID))
 	if err != nil && !req.ForceDelete {
 		return err
 	}
-
-	if strings.HasPrefix(app.Version, "5.6") {
-		if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop user '%s'@'%s'", db.Username, db.Permission)); err != nil && !req.ForceDelete {
-			return err
-		}
-	} else {
-		if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", db.Username, db.Permission)); err != nil && !req.ForceDelete {
-			return err
-		}
-	}
-	if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database if exists `%s`", db.Name)); err != nil && !req.ForceDelete {
+	if err := cli.Delete(client.DeleteInfo{
+		Name:       db.Name,
+		Version:    version,
+		Username:   db.Username,
+		Permission: db.Permission,
+		Timeout:    300,
+	}); err != nil {
+		return err
+	}
+
+	app, err := appInstallRepo.LoadBaseInfo("mysql", "")
+	if err != nil && !req.ForceDelete {
 		return err
 	}
-	global.LOG.Info("execute delete database sql successful, now start to drop uploads and records")
 
 	uploadDir := fmt.Sprintf("%s/1panel/uploads/database/mysql/%s/%s", global.CONF.System.BaseDir, app.Name, db.Name)
 	if _, err := os.Stat(uploadDir); err == nil {
@@ -192,66 +212,55 @@ func (u *MysqlService) ChangePassword(info dto.ChangeDBInfo) error {
 	if cmd.CheckIllegal(info.Value) {
 		return buserr.New(constant.ErrCmdIllegal)
 	}
-
+	cli, version, err := loadClientByID(info.ID)
+	if err != nil {
+		return err
+	}
 	var (
-		mysql model.DatabaseMysql
-		err   error
+		mysqlData    model.DatabaseMysql
+		passwordInfo client.PasswordChangeInfo
 	)
+	passwordInfo.Password = info.Value
+	passwordInfo.Timeout = 300
+	passwordInfo.Version = version
+
 	if info.ID != 0 {
-		mysql, err = mysqlRepo.Get(commonRepo.WithByID(info.ID))
+		mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(info.ID))
 		if err != nil {
 			return err
 		}
+		passwordInfo.Name = mysqlData.Name
+		passwordInfo.Username = mysqlData.Username
+		passwordInfo.Permission = mysqlData.Permission
+	} else {
+		passwordInfo.Username = "root"
 	}
-	app, err := appInstallRepo.LoadBaseInfo("mysql", "")
-	if err != nil {
+	if err := cli.ChangePassword(passwordInfo); err != nil {
 		return err
 	}
 
-	passwordChangeCMD := fmt.Sprintf("set password for '%s'@'%s' = password('%s')", mysql.Username, mysql.Permission, info.Value)
-	if !strings.HasPrefix(app.Version, "5.7") && !strings.HasPrefix(app.Version, "5.6") {
-		passwordChangeCMD = fmt.Sprintf("ALTER USER '%s'@'%s' IDENTIFIED WITH mysql_native_password BY '%s';", mysql.Username, mysql.Permission, info.Value)
-	}
 	if info.ID != 0 {
-		appRess, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(app.ID), appInstallResourceRepo.WithResourceId(mysql.ID))
-		for _, appRes := range appRess {
-			appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(appRes.AppInstallId))
-			if err != nil {
-				return err
-			}
-			appModel, err := appRepo.GetFirst(commonRepo.WithByID(appInstall.AppId))
-			if err != nil {
-				return err
-			}
+		// appRess, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(app.ID), appInstallResourceRepo.WithResourceId(mysqlData.ID))
+		// for _, appRes := range appRess {
+		// 	appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(appRes.AppInstallId))
+		// 	if err != nil {
+		// 		return err
+		// 	}
+		// 	appModel, err := appRepo.GetFirst(commonRepo.WithByID(appInstall.AppId))
+		// 	if err != nil {
+		// 		return err
+		// 	}
 
-			global.LOG.Infof("start to update mysql password used by app %s-%s", appModel.Key, appInstall.Name)
-			if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "user-password", true, info.Value); err != nil {
-				return err
-			}
-		}
-		if err := excuteSql(app.ContainerName, app.Password, passwordChangeCMD); err != nil {
-			return err
-		}
+		// 	global.LOG.Infof("start to update mysql password used by app %s-%s", appModel.Key, appInstall.Name)
+		// 	if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "user-password", true, info.Value); err != nil {
+		// 		return err
+		// 	}
+		// }
 		global.LOG.Info("excute password change sql successful")
-		_ = mysqlRepo.Update(mysql.ID, map[string]interface{}{"password": info.Value})
+		_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"password": info.Value})
 		return nil
 	}
 
-	hosts, err := excuteSqlForRows(app.ContainerName, app.Password, "select host from mysql.user where user='root';")
-	if err != nil {
-		return err
-	}
-	for _, host := range hosts {
-		if host == "%" || host == "localhost" {
-			passwordRootChangeCMD := fmt.Sprintf("set password for 'root'@'%s' = password('%s')", host, info.Value)
-			if !strings.HasPrefix(app.Version, "5.7") && !strings.HasPrefix(app.Version, "5.6") {
-				passwordRootChangeCMD = fmt.Sprintf("alter user 'root'@'%s' identified with mysql_native_password BY '%s';", host, info.Value)
-			}
-			if err := excuteSql(app.ContainerName, app.Password, passwordRootChangeCMD); err != nil {
-				return err
-			}
-		}
-	}
 	if err := updateInstallInfoInDB("mysql", "", "password", false, info.Value); err != nil {
 		return err
 	}
@@ -265,71 +274,36 @@ func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
 	if cmd.CheckIllegal(info.Value) {
 		return buserr.New(constant.ErrCmdIllegal)
 	}
-	var (
-		mysql model.DatabaseMysql
-		err   error
-	)
-	if info.ID != 0 {
-		mysql, err = mysqlRepo.Get(commonRepo.WithByID(info.ID))
-		if err != nil {
-			return err
-		}
-		if info.Value == mysql.Permission {
-			return nil
-		}
-	}
-	app, err := appInstallRepo.LoadBaseInfo("mysql", "")
+	cli, version, err := loadClientByID(info.ID)
 	if err != nil {
 		return err
 	}
-	if info.ID == 0 {
-		mysql.Name = "*"
-		mysql.Username = "root"
-		mysql.Permission = "%"
-		mysql.Password = app.Password
-	}
+	var (
+		mysqlData  model.DatabaseMysql
+		accessInfo client.AccessChangeInfo
+	)
+	accessInfo.Permission = info.Value
+	accessInfo.Timeout = 300
+	accessInfo.Version = version
 
-	if info.Value != mysql.Permission {
-		var userlist []string
-		if strings.Contains(mysql.Permission, ",") {
-			userlist = strings.Split(mysql.Permission, ",")
-		} else {
-			userlist = append(userlist, mysql.Permission)
-		}
-		for _, user := range userlist {
-			if len(user) != 0 {
-				if strings.HasPrefix(app.Version, "5.6") {
-					if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop user '%s'@'%s'", mysql.Username, user)); err != nil {
-						return err
-					}
-				} else {
-					if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", mysql.Username, user)); err != nil {
-						return err
-					}
-				}
-			}
-		}
-		if info.ID == 0 {
-			return nil
+	if info.ID != 0 {
+		mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(info.ID))
+		if err != nil {
+			return err
 		}
+		accessInfo.Name = mysqlData.Name
+		accessInfo.Username = mysqlData.Username
+		accessInfo.OldPermission = mysqlData.Permission
+	} else {
+		accessInfo.Username = "root"
 	}
-
-	if err := u.createUser(app.ContainerName, app.Password, app.Version, dto.MysqlDBCreate{
-		Username:   mysql.Username,
-		Name:       mysql.Name,
-		Permission: info.Value,
-		Password:   mysql.Password,
-	}); err != nil {
+	if err := cli.ChangeAccess(accessInfo); err != nil {
 		return err
 	}
-	if err := excuteSql(app.ContainerName, app.Password, "flush privileges"); err != nil {
-		return err
-	}
-	if info.ID == 0 {
-		return nil
-	}
 
-	_ = mysqlRepo.Update(mysql.ID, map[string]interface{}{"permission": info.Value})
+	if mysqlData.ID != 0 {
+		_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"permission": info.Value})
+	}
 
 	return nil
 }
@@ -493,53 +467,6 @@ func (u *MysqlService) LoadStatus() (*dto.MysqlStatus, error) {
 	return &info, nil
 }
 
-func (u *MysqlService) createUser(container, password, version string, req dto.MysqlDBCreate) error {
-	var userlist []string
-	if strings.Contains(req.Permission, ",") {
-		ips := strings.Split(req.Permission, ",")
-		for _, ip := range ips {
-			if len(ip) != 0 {
-				userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", req.Username, ip))
-			}
-		}
-	} else {
-		userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", req.Username, req.Permission))
-	}
-
-	for _, user := range userlist {
-		if err := excSQL(container, password, fmt.Sprintf("create user %s identified by '%s';", user, req.Password)); err != nil {
-			if strings.Contains(err.Error(), "ERROR 1396") {
-				handleCreateError(container, password, req.Name, userlist, false)
-				return buserr.New(constant.ErrUserIsExist)
-			}
-			handleCreateError(container, password, req.Name, userlist, true)
-			return err
-		}
-		grantStr := fmt.Sprintf("grant all privileges on `%s`.* to %s", req.Name, user)
-		if req.Name == "*" {
-			grantStr = fmt.Sprintf("grant all privileges on *.* to %s", user)
-		}
-		if strings.HasPrefix(version, "5.7") || strings.HasPrefix(version, "5.6") {
-			grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, req.Password)
-		}
-		if err := excSQL(container, password, grantStr); err != nil {
-			handleCreateError(container, password, req.Name, userlist, true)
-			return err
-		}
-	}
-	return nil
-}
-func handleCreateError(contaienr, password, dbName string, userlist []string, dropUser bool) {
-	_ = excSQL(contaienr, password, fmt.Sprintf("drop database `%s`", dbName))
-	if dropUser {
-		for _, user := range userlist {
-			if err := excSQL(contaienr, password, fmt.Sprintf("drop user if exists %s", user)); err != nil {
-				global.LOG.Errorf("drop user failed, err: %v", err)
-			}
-		}
-	}
-}
-
 func excuteSqlForMaps(containerName, password, command string) (map[string]string, error) {
 	cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
 	stdout, err := cmd.CombinedOutput()
@@ -569,31 +496,6 @@ func excuteSqlForRows(containerName, password, command string) ([]string, error)
 	return strings.Split(stdStr, "\n"), nil
 }
 
-func excuteSql(containerName, password, command string) error {
-	cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
-	stdout, err := cmd.CombinedOutput()
-	stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
-	if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
-		return errors.New(stdStr)
-	}
-	return nil
-}
-
-func excSQL(containerName, password, command string) error {
-	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
-	defer cancel()
-	cmd := exec.CommandContext(ctx, "docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
-	stdout, err := cmd.CombinedOutput()
-	if ctx.Err() == context.DeadlineExceeded {
-		return buserr.New(constant.ErrExecTimeOut)
-	}
-	stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
-	if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
-		return errors.New(stdStr)
-	}
-	return nil
-}
-
 func updateMyCnf(oldFiles []string, group string, param string, value interface{}) []string {
 	isOn := false
 	hasGroup := false
@@ -634,3 +536,46 @@ func updateMyCnf(oldFiles []string, group string, param string, value interface{
 	}
 	return newFiles
 }
+
+func loadClientByID(id uint) (mysql.MysqlClient, string, error) {
+	var (
+		mysqlData model.DatabaseMysql
+		dbInfo    client.DBInfo
+		version   string
+		err       error
+	)
+	if id != 0 {
+		mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(id))
+		if err != nil {
+			return nil, "", err
+		}
+	}
+
+	if mysqlData.From != "local" {
+		databaseItem, err := remoteDBRepo.Get(commonRepo.WithByName(mysqlData.From))
+		if err != nil {
+			return nil, "", err
+		}
+		dbInfo.Address = databaseItem.Address
+		dbInfo.Port = databaseItem.Port
+		dbInfo.Username = databaseItem.Username
+		dbInfo.Password = databaseItem.Password
+		version = databaseItem.Version
+
+	} else {
+		app, err := appInstallRepo.LoadBaseInfo("mysql", "")
+		if err != nil {
+			return nil, "", err
+		}
+		dbInfo.Address = app.ContainerName
+		dbInfo.Username = "root"
+		dbInfo.Password = app.Password
+		version = app.Version
+	}
+
+	cli, err := mysql.NewMysqlClient(dbInfo)
+	if err != nil {
+		return nil, "", err
+	}
+	return cli, version, nil
+}
diff --git a/backend/app/service/entry.go b/backend/app/service/entry.go
index 64f3bf25e..fa8f9f238 100644
--- a/backend/app/service/entry.go
+++ b/backend/app/service/entry.go
@@ -12,7 +12,8 @@ var (
 	appInstallRepo         = repo.NewIAppInstallRepo()
 	appInstallResourceRepo = repo.NewIAppInstallResourceRpo()
 
-	mysqlRepo = repo.NewIMysqlRepo()
+	mysqlRepo    = repo.NewIMysqlRepo()
+	remoteDBRepo = repo.NewIRemoteDBRepo()
 
 	imageRepoRepo = repo.NewIImageRepoRepo()
 	composeRepo   = repo.NewIComposeTemplateRepo()
diff --git a/backend/app/service/remote_db.go b/backend/app/service/remote_db.go
new file mode 100644
index 000000000..b0e2962c9
--- /dev/null
+++ b/backend/app/service/remote_db.go
@@ -0,0 +1,108 @@
+package service
+
+import (
+	"github.com/1Panel-dev/1Panel/backend/app/dto"
+	"github.com/1Panel-dev/1Panel/backend/constant"
+	"github.com/1Panel-dev/1Panel/backend/utils/mysql"
+	"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
+	"github.com/jinzhu/copier"
+	"github.com/pkg/errors"
+)
+
+type RemoteDBService struct{}
+
+type IRemoteDBService interface {
+	SearchWithPage(search dto.RemoteDBSearch) (int64, interface{}, error)
+	Create(req dto.RemoteDBCreate) error
+	Update(req dto.RemoteDBUpdate) error
+	Delete(id uint) error
+	List(dbType string) ([]dto.RemoteDBOption, error)
+}
+
+func NewIRemoteDBService() IRemoteDBService {
+	return &RemoteDBService{}
+}
+
+func (u *RemoteDBService) SearchWithPage(search dto.RemoteDBSearch) (int64, interface{}, error) {
+	total, dbs, err := remoteDBRepo.Page(search.Page, search.PageSize,
+		commonRepo.WithByType(search.Type),
+		commonRepo.WithLikeName(search.Info),
+		remoteDBRepo.WithoutByFrom("local"),
+	)
+	var datas []dto.RemoteDBInfo
+	for _, db := range dbs {
+		var item dto.RemoteDBInfo
+		if err := copier.Copy(&item, &db); err != nil {
+			return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
+		}
+		datas = append(datas, item)
+	}
+	return total, datas, err
+}
+
+func (u *RemoteDBService) List(dbType string) ([]dto.RemoteDBOption, error) {
+	dbs, err := remoteDBRepo.GetList(commonRepo.WithByType(dbType), remoteDBRepo.WithoutByFrom("local"))
+	var datas []dto.RemoteDBOption
+	for _, db := range dbs {
+		var item dto.RemoteDBOption
+		if err := copier.Copy(&item, &db); err != nil {
+			return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
+		}
+		datas = append(datas, item)
+	}
+	return datas, err
+}
+
+func (u *RemoteDBService) Create(req dto.RemoteDBCreate) error {
+	db, _ := remoteDBRepo.Get(commonRepo.WithByName(req.Name))
+	if db.ID != 0 {
+		return constant.ErrRecordExist
+	}
+	if _, err := mysql.NewMysqlClient(client.DBInfo{
+		From:     "remote",
+		Address:  req.Address,
+		Port:     req.Port,
+		Username: req.Username,
+		Password: req.Password,
+		Timeout:  300,
+	}); err != nil {
+		return err
+	}
+	if err := copier.Copy(&db, &req); err != nil {
+		return errors.WithMessage(constant.ErrStructTransform, err.Error())
+	}
+	if err := remoteDBRepo.Create(&db); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (u *RemoteDBService) Delete(id uint) error {
+	db, _ := remoteDBRepo.Get(commonRepo.WithByID(id))
+	if db.ID == 0 {
+		return constant.ErrRecordNotFound
+	}
+	return remoteDBRepo.Delete(commonRepo.WithByID(id))
+}
+
+func (u *RemoteDBService) Update(req dto.RemoteDBUpdate) error {
+	if _, err := mysql.NewMysqlClient(client.DBInfo{
+		From:     "remote",
+		Address:  req.Address,
+		Port:     req.Port,
+		Username: req.Username,
+		Password: req.Password,
+		Timeout:  300,
+	}); err != nil {
+		return err
+	}
+
+	upMap := make(map[string]interface{})
+	upMap["version"] = req.Version
+	upMap["address"] = req.Address
+	upMap["port"] = req.Port
+	upMap["username"] = req.Username
+	upMap["password"] = req.Password
+	upMap["description"] = req.Description
+	return remoteDBRepo.Update(req.ID, upMap)
+}
diff --git a/backend/init/migration/migrations/init.go b/backend/init/migration/migrations/init.go
index 9bd5c3ec1..f7d65bcd2 100644
--- a/backend/init/migration/migrations/init.go
+++ b/backend/init/migration/migrations/init.go
@@ -481,9 +481,9 @@ var EncryptHostPassword = &gormigrate.Migration{
 }
 
 var AddRemoteDB = &gormigrate.Migration{
-	ID: "20230718-add-remote-db",
+	ID: "20230720-add-remote-db",
 	Migrate: func(tx *gorm.DB) error {
-		if err := tx.AutoMigrate(&model.Database{}); err != nil {
+		if err := tx.AutoMigrate(&model.RemoteDB{}); err != nil {
 			return err
 		}
 		return nil
diff --git a/backend/router/ro_database.go b/backend/router/ro_database.go
index 8e2b9b7e6..1d32e48d7 100644
--- a/backend/router/ro_database.go
+++ b/backend/router/ro_database.go
@@ -40,5 +40,11 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
 		cmdRouter.POST("/redis/conf/update", baseApi.UpdateRedisConf)
 		cmdRouter.POST("/redis/conffile/update", baseApi.UpdateRedisConfByFile)
 		cmdRouter.POST("/redis/persistence/update", baseApi.UpdateRedisPersistenceConf)
+
+		cmdRouter.POST("/remote", baseApi.CreateRemoteDB)
+		cmdRouter.POST("/remote/list/:type", baseApi.ListRemoteDB)
+		cmdRouter.POST("/remote/update", baseApi.UpdateRemoteDB)
+		cmdRouter.POST("/remote/search", baseApi.SearchRemoteDB)
+		cmdRouter.POST("/remote/del", baseApi.DeleteRemoteDB)
 	}
 }
diff --git a/backend/utils/mysql/client.go b/backend/utils/mysql/client.go
index 9d064fb95..82e204c86 100644
--- a/backend/utils/mysql/client.go
+++ b/backend/utils/mysql/client.go
@@ -22,19 +22,22 @@ type MysqlClient interface {
 }
 
 func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) {
-	if conn.Type == "remote" {
-		connArgs := fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=utf8", conn.UserName, conn.Password, conn.Address, conn.Port)
+	if conn.From == "remote" {
+		connArgs := fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=utf8", conn.Username, conn.Password, conn.Address, conn.Port)
 		db, err := sql.Open("mysql", connArgs)
 		if err != nil {
 			return nil, err
 		}
+		if err := db.Ping(); err != nil {
+			return nil, err
+		}
 		return client.NewRemote(db), nil
 	}
-	if conn.Type == "local" {
-		if cmd.CheckIllegal(conn.Address, conn.UserName, conn.Password) {
+	if conn.From == "local" {
+		if cmd.CheckIllegal(conn.Address, conn.Username, conn.Password) {
 			return nil, buserr.New(constant.ErrCmdIllegal)
 		}
-		connArgs := []string{"exec", conn.Address, "mysql", "-u" + conn.UserName, "-p" + conn.Password + "-e"}
+		connArgs := []string{"exec", conn.Address, "mysql", "-u" + conn.Username, "-p" + conn.Password + "-e"}
 		return client.NewLocal(connArgs, conn.Address), nil
 	}
 	return nil, errors.New("no such type")
diff --git a/backend/utils/mysql/client/info.go b/backend/utils/mysql/client/info.go
index 8d478d32c..85e2c8195 100644
--- a/backend/utils/mysql/client/info.go
+++ b/backend/utils/mysql/client/info.go
@@ -1,12 +1,11 @@
 package client
 
 type DBInfo struct {
-	Type     string `json:"type"` // local remote
+	From     string `json:"from"` // local remote
 	Address  string `json:"address"`
 	Port     uint   `json:"port"`
-	UserName string `json:"userName"`
+	Username string `json:"userName"`
 	Password string `json:"password"`
-	Format   string `json:"format"`
 
 	Timeout uint `json:"timeout"` // second
 }
@@ -15,7 +14,7 @@ type CreateInfo struct {
 	Name       string `json:"name"`
 	Format     string `json:"format"`
 	Version    string `json:"version"`
-	UserName   string `json:"userName"`
+	Username   string `json:"userName"`
 	Password   string `json:"password"`
 	Permission string `json:"permission"`
 
@@ -25,7 +24,7 @@ type CreateInfo struct {
 type DeleteInfo struct {
 	Name       string `json:"name"`
 	Version    string `json:"version"`
-	UserName   string `json:"userName"`
+	Username   string `json:"userName"`
 	Permission string `json:"permission"`
 
 	ForceDelete bool `json:"forceDelete"`
@@ -35,7 +34,7 @@ type DeleteInfo struct {
 type PasswordChangeInfo struct {
 	Name       string `json:"name"`
 	Version    string `json:"version"`
-	UserName   string `json:"userName"`
+	Username   string `json:"userName"`
 	Password   string `json:"password"`
 	Permission string `json:"permission"`
 
@@ -45,7 +44,7 @@ type PasswordChangeInfo struct {
 type AccessChangeInfo struct {
 	Name          string `json:"name"`
 	Version       string `json:"version"`
-	UserName      string `json:"userName"`
+	Username      string `json:"userName"`
 	OldPermission string `json:"oldPermission"`
 	Permission    string `json:"permission"`
 
diff --git a/backend/utils/mysql/client/local.go b/backend/utils/mysql/client/local.go
index 0c61e0a23..4508a6d56 100644
--- a/backend/utils/mysql/client/local.go
+++ b/backend/utils/mysql/client/local.go
@@ -31,7 +31,7 @@ func (r *Local) Create(info CreateInfo) error {
 		return err
 	}
 
-	if err := r.CreateUser(CreateInfo{Name: info.Name, Version: info.Version, UserName: info.UserName, Permission: info.Permission, Timeout: info.Timeout}); err != nil {
+	if err := r.CreateUser(CreateInfo{Name: info.Name, Version: info.Version, Username: info.Username, Permission: info.Permission, Timeout: info.Timeout}); err != nil {
 		return err
 	}
 
@@ -44,11 +44,11 @@ func (r *Local) CreateUser(info CreateInfo) error {
 		ips := strings.Split(info.Permission, ",")
 		for _, ip := range ips {
 			if len(ip) != 0 {
-				userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.UserName, ip))
+				userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.Username, ip))
 			}
 		}
 	} else {
-		userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.UserName, info.Permission))
+		userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.Username, info.Permission))
 	}
 
 	for _, user := range userlist {
@@ -56,7 +56,7 @@ func (r *Local) CreateUser(info CreateInfo) error {
 			_ = r.Delete(DeleteInfo{
 				Name:        info.Name,
 				Version:     info.Version,
-				UserName:    info.UserName,
+				Username:    info.Username,
 				Permission:  info.Permission,
 				ForceDelete: true,
 				Timeout:     300})
@@ -76,7 +76,7 @@ func (r *Local) CreateUser(info CreateInfo) error {
 			_ = r.Delete(DeleteInfo{
 				Name:        info.Name,
 				Version:     info.Version,
-				UserName:    info.UserName,
+				Username:    info.Username,
 				Permission:  info.Permission,
 				ForceDelete: true,
 				Timeout:     300})
@@ -92,11 +92,11 @@ func (r *Local) Delete(info DeleteInfo) error {
 		ips := strings.Split(info.Permission, ",")
 		for _, ip := range ips {
 			if len(ip) != 0 {
-				userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.UserName, ip))
+				userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.Username, ip))
 			}
 		}
 	} else {
-		userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.UserName, info.Permission))
+		userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.Username, info.Permission))
 	}
 
 	for _, user := range userlist {
@@ -123,17 +123,17 @@ func (r *Local) Delete(info DeleteInfo) error {
 }
 
 func (r *Local) ChangePassword(info PasswordChangeInfo) error {
-	if info.UserName != "root" {
+	if info.Username != "root" {
 		var userlist []string
 		if strings.Contains(info.Permission, ",") {
 			ips := strings.Split(info.Permission, ",")
 			for _, ip := range ips {
 				if len(ip) != 0 {
-					userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.UserName, ip))
+					userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.Username, ip))
 				}
 			}
 		} else {
-			userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.UserName, info.Permission))
+			userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.Username, info.Permission))
 		}
 
 		for _, user := range userlist {
@@ -168,24 +168,27 @@ func (r *Local) ChangePassword(info PasswordChangeInfo) error {
 }
 
 func (r *Local) ChangeAccess(info AccessChangeInfo) error {
-	if info.UserName == "root" {
+	if info.Username == "root" {
 		info.OldPermission = "%"
 		info.Name = "*"
 	}
 	if info.Permission != info.OldPermission {
 		if err := r.Delete(DeleteInfo{
 			Version:     info.Version,
-			UserName:    info.UserName,
+			Username:    info.Username,
 			Permission:  info.OldPermission,
 			ForceDelete: true,
 			Timeout:     300}); err != nil {
 			return err
 		}
-		if info.UserName == "root" {
+		if info.Username == "root" {
 			return nil
 		}
 	}
-	if err := r.CreateUser(CreateInfo{Name: info.Name, Version: info.Version, UserName: info.UserName, Permission: info.Permission, Timeout: info.Timeout}); err != nil {
+	if err := r.CreateUser(CreateInfo{Name: info.Name, Version: info.Version, Username: info.Username, Permission: info.Permission, Timeout: info.Timeout}); err != nil {
+		return err
+	}
+	if err := r.ExecSQL("flush privileges", 300); err != nil {
 		return err
 	}
 	return nil
diff --git a/backend/utils/mysql/client/remote.go b/backend/utils/mysql/client/remote.go
index 80a2158fe..083242cfd 100644
--- a/backend/utils/mysql/client/remote.go
+++ b/backend/utils/mysql/client/remote.go
@@ -29,7 +29,7 @@ func (r *Remote) Create(info CreateInfo) error {
 		return err
 	}
 
-	if err := r.CreateUser(CreateInfo{Name: info.Name, Version: info.Version, UserName: info.UserName, Permission: info.Permission, Timeout: info.Timeout}); err != nil {
+	if err := r.CreateUser(CreateInfo{Name: info.Name, Version: info.Version, Username: info.Username, Permission: info.Permission, Timeout: info.Timeout}); err != nil {
 		return err
 	}
 
@@ -42,11 +42,11 @@ func (r *Remote) CreateUser(info CreateInfo) error {
 		ips := strings.Split(info.Permission, ",")
 		for _, ip := range ips {
 			if len(ip) != 0 {
-				userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.UserName, ip))
+				userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.Username, ip))
 			}
 		}
 	} else {
-		userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.UserName, info.Permission))
+		userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.Username, info.Permission))
 	}
 
 	for _, user := range userlist {
@@ -54,7 +54,7 @@ func (r *Remote) CreateUser(info CreateInfo) error {
 			_ = r.Delete(DeleteInfo{
 				Name:        info.Name,
 				Version:     info.Version,
-				UserName:    info.UserName,
+				Username:    info.Username,
 				Permission:  info.Permission,
 				ForceDelete: true,
 				Timeout:     300})
@@ -74,7 +74,7 @@ func (r *Remote) CreateUser(info CreateInfo) error {
 			_ = r.Delete(DeleteInfo{
 				Name:        info.Name,
 				Version:     info.Version,
-				UserName:    info.UserName,
+				Username:    info.Username,
 				Permission:  info.Permission,
 				ForceDelete: true,
 				Timeout:     300})
@@ -90,11 +90,11 @@ func (r *Remote) Delete(info DeleteInfo) error {
 		ips := strings.Split(info.Permission, ",")
 		for _, ip := range ips {
 			if len(ip) != 0 {
-				userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.UserName, ip))
+				userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.Username, ip))
 			}
 		}
 	} else {
-		userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.UserName, info.Permission))
+		userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.Username, info.Permission))
 	}
 
 	for _, user := range userlist {
@@ -121,17 +121,17 @@ func (r *Remote) Delete(info DeleteInfo) error {
 }
 
 func (r *Remote) ChangePassword(info PasswordChangeInfo) error {
-	if info.UserName != "root" {
+	if info.Username != "root" {
 		var userlist []string
 		if strings.Contains(info.Permission, ",") {
 			ips := strings.Split(info.Permission, ",")
 			for _, ip := range ips {
 				if len(ip) != 0 {
-					userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.UserName, ip))
+					userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.Username, ip))
 				}
 			}
 		} else {
-			userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.UserName, info.Permission))
+			userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", info.Username, info.Permission))
 		}
 
 		for _, user := range userlist {
@@ -166,24 +166,27 @@ func (r *Remote) ChangePassword(info PasswordChangeInfo) error {
 }
 
 func (r *Remote) ChangeAccess(info AccessChangeInfo) error {
-	if info.UserName == "root" {
+	if info.Username == "root" {
 		info.OldPermission = "%"
 		info.Name = "*"
 	}
 	if info.Permission != info.OldPermission {
 		if err := r.Delete(DeleteInfo{
 			Version:     info.Version,
-			UserName:    info.UserName,
+			Username:    info.Username,
 			Permission:  info.OldPermission,
 			ForceDelete: true,
 			Timeout:     300}); err != nil {
 			return err
 		}
-		if info.UserName == "root" {
+		if info.Username == "root" {
 			return nil
 		}
 	}
-	if err := r.CreateUser(CreateInfo{Name: info.Name, Version: info.Version, UserName: info.UserName, Permission: info.Permission, Timeout: info.Timeout}); err != nil {
+	if err := r.CreateUser(CreateInfo{Name: info.Name, Version: info.Version, Username: info.Username, Permission: info.Permission, Timeout: info.Timeout}); err != nil {
+		return err
+	}
+	if err := r.ExecSQL("flush privileges", 300); err != nil {
 		return err
 	}
 	return nil
diff --git a/frontend/src/api/interface/app.ts b/frontend/src/api/interface/app.ts
index ed05a71d3..61e456e26 100644
--- a/frontend/src/api/interface/app.ts
+++ b/frontend/src/api/interface/app.ts
@@ -131,6 +131,7 @@ export namespace App {
 
     export interface DatabaseConnInfo {
         password: string;
+        privilege: boolean;
         serviceName: string;
         port: number;
     }
diff --git a/frontend/src/api/interface/database.ts b/frontend/src/api/interface/database.ts
index 757f130a4..22fe0520d 100644
--- a/frontend/src/api/interface/database.ts
+++ b/frontend/src/api/interface/database.ts
@@ -167,6 +167,40 @@ export namespace Database {
         createdAt: Date;
         name: string;
         type: string;
+        version: string;
+        from: string;
+        address: string;
+        port: number;
+        username: string;
+        password: string;
+        description: string;
+    }
+    export interface SearchRemoteDBPage {
+        info: string;
+        type: string;
+        page: number;
+        pageSize: number;
+        orderBy?: string;
+        order?: string;
+    }
+    export interface RemoteDBOption {
+        id: number;
+        name: string;
+        address: string;
+    }
+    export interface RemoteDBCreate {
+        name: string;
+        version: string;
+        from: string;
+        address: string;
+        port: number;
+        username: string;
+        password: string;
+        description: string;
+    }
+    export interface RemoteDBUpdate {
+        id: number;
+        version: string;
         address: string;
         port: number;
         username: string;
diff --git a/frontend/src/api/modules/database.ts b/frontend/src/api/modules/database.ts
index 6039668fb..609884c6a 100644
--- a/frontend/src/api/modules/database.ts
+++ b/frontend/src/api/modules/database.ts
@@ -85,13 +85,16 @@ export const updateRedisConfByFile = (params: Database.RedisConfUpdateByFile) =>
 };
 
 // remote
-export const searchRemoteDBs = (params: SearchWithPage) => {
+export const searchRemoteDBs = (params: Database.SearchRemoteDBPage) => {
     return http.post<ResPage<Database.RemoteDBInfo>>(`/databases/remote/search`, params);
 };
-export const addRemoteDB = (params: Database.RemoteDBInfo) => {
+export const listRemoteDBs = (type: string) => {
+    return http.get<Array<Database.RemoteDBOption>>(`/databases/remote/list/${type}`);
+};
+export const addRemoteDB = (params: Database.RemoteDBCreate) => {
     return http.post(`/databases/remote`, params);
 };
-export const editRemoteDB = (params: Database.RemoteDBInfo) => {
+export const editRemoteDB = (params: Database.RemoteDBUpdate) => {
     return http.post(`/databases/remote/update`, params);
 };
 export const deleteRemoteDB = (id: number) => {
diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts
index aecaaa148..9d849ee2d 100644
--- a/frontend/src/lang/modules/zh.ts
+++ b/frontend/src/lang/modules/zh.ts
@@ -330,6 +330,13 @@ const message = {
 
         confChange: '配置修改',
 
+        remoteDB: '远程数据库',
+        createRemoteDB: '创建远程数据库',
+        editRemoteDB: '编辑远程数据库',
+        localDB: '本地数据库',
+        address: '数据库地址',
+        version: '数据库版本',
+
         selectFile: '选择文件',
         dropHelper: '将上传文件拖拽到此处,或者',
         clickHelper: '点击上传',
diff --git a/frontend/src/routers/modules/database.ts b/frontend/src/routers/modules/database.ts
index d46f46c24..efdb36754 100644
--- a/frontend/src/routers/modules/database.ts
+++ b/frontend/src/routers/modules/database.ts
@@ -27,6 +27,16 @@ const databaseRouter = {
                         requiresAuth: false,
                     },
                 },
+                {
+                    path: 'mysql/remote',
+                    name: 'MySQL-Remote',
+                    component: () => import('@/views/database/mysql/remote/index.vue'),
+                    hidden: true,
+                    meta: {
+                        activeMenu: '/databases',
+                        requiresAuth: false,
+                    },
+                },
                 {
                     path: 'redis',
                     name: 'Redis',
diff --git a/frontend/src/views/database/mysql/index.vue b/frontend/src/views/database/mysql/index.vue
index a23e7a6fd..2d31106f5 100644
--- a/frontend/src/views/database/mysql/index.vue
+++ b/frontend/src/views/database/mysql/index.vue
@@ -20,8 +20,8 @@
                         <el-button @click="onChangeRootPassword" type="primary" plain>
                             {{ $t('database.databaseConnInfo') }}
                         </el-button>
-                        <el-button @click="onChangeAccess" type="primary" plain>
-                            {{ $t('database.remoteAccess') }}
+                        <el-button @click="goRemoteDB" type="primary" plain>
+                            {{ $t('database.remoteDB') }}
                         </el-button>
                         <el-button @click="goDashboard" icon="Position" type="primary" plain>phpMyAdmin</el-button>
                     </el-col>
@@ -134,7 +134,6 @@
 
         <PasswordDialog ref="passwordRef" @search="search" />
         <RootPasswordDialog ref="rootPasswordRef" />
-        <RemoteAccessDialog ref="remoteAccessRef" />
         <UploadDialog ref="uploadRef" />
         <OperateDialog @search="search" ref="dialogRef" />
         <Backups ref="dialogBackupRef" />
@@ -151,7 +150,6 @@ import OperateDialog from '@/views/database/mysql/create/index.vue';
 import DeleteDialog from '@/views/database/mysql/delete/index.vue';
 import PasswordDialog from '@/views/database/mysql/password/index.vue';
 import RootPasswordDialog from '@/views/database/mysql/root-password/index.vue';
-import RemoteAccessDialog from '@/views/database/mysql/remote/index.vue';
 import AppResources from '@/views/database/mysql/check/index.vue';
 import Setting from '@/views/database/mysql/setting/index.vue';
 import AppStatus from '@/components/app-status/index.vue';
@@ -160,7 +158,7 @@ import UploadDialog from '@/components/upload/index.vue';
 import PortJumpDialog from '@/components/port-jump/index.vue';
 import { dateFormat } from '@/utils/util';
 import { reactive, ref } from 'vue';
-import { deleteCheckMysqlDB, loadRemoteAccess, searchMysqlDBs, updateMysqlDescription } from '@/api/modules/database';
+import { deleteCheckMysqlDB, searchMysqlDBs, updateMysqlDescription } from '@/api/modules/database';
 import i18n from '@/lang';
 import { Database } from '@/api/interface/database';
 import { App } from '@/api/interface/app';
@@ -222,13 +220,8 @@ const onChangeRootPassword = async () => {
     rootPasswordRef.value!.acceptParams();
 };
 
-const remoteAccessRef = ref();
-const onChangeAccess = async () => {
-    const res = await loadRemoteAccess();
-    let param = {
-        privilege: res.data,
-    };
-    remoteAccessRef.value!.acceptParams(param);
+const goRemoteDB = async () => {
+    router.push({ name: 'MySQL-Remote' });
 };
 
 const passwordRef = ref();
diff --git a/frontend/src/views/database/mysql/remote/index.vue b/frontend/src/views/database/mysql/remote/index.vue
index 3de162327..237237ea8 100644
--- a/frontend/src/views/database/mysql/remote/index.vue
+++ b/frontend/src/views/database/mysql/remote/index.vue
@@ -1,98 +1,181 @@
 <template>
-    <el-drawer v-model="dialogVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
-        <template #header>
-            <DrawerHeader :header="$t('database.remoteAccess')" :back="handleClose" />
-        </template>
-        <el-form @submit.prevent v-loading="loading" ref="formRef" :model="form" label-position="top">
-            <el-row type="flex" justify="center">
-                <el-col :span="22">
-                    <el-form-item :label="$t('database.remoteAccess')" :rules="Rules.requiredInput" prop="privilege">
-                        <el-switch v-model="form.privilege" />
-                        <span class="input-help">{{ $t('database.remoteConnHelper') }}</span>
-                    </el-form-item>
-                </el-col>
-            </el-row>
-        </el-form>
+    <div v-loading="loading">
+        <LayoutContent>
+            <template #title>
+                <back-button name="MySQL" :header="'MySQL ' + $t('database.remoteDB')" />
+            </template>
+            <template #toolbar>
+                <el-row>
+                    <el-col :xs="24" :sm="20" :md="20" :lg="20" :xl="20">
+                        <el-button type="primary" @click="onOpenDialog('create')">
+                            {{ $t('database.createRemoteDB') }}
+                        </el-button>
+                    </el-col>
+                    <el-col :xs="24" :sm="4" :md="4" :lg="4" :xl="4">
+                        <div class="search-button">
+                            <el-input
+                                v-model="searchName"
+                                clearable
+                                @clear="search()"
+                                suffix-icon="Search"
+                                @keyup.enter="search()"
+                                @change="search()"
+                                :placeholder="$t('commons.button.search')"
+                            ></el-input>
+                        </div>
+                    </el-col>
+                </el-row>
+            </template>
+            <template #main>
+                <ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data">
+                    <el-table-column :label="$t('commons.table.name')" prop="name" sortable />
+                    <el-table-column :label="$t('database.address')" prop="address" />
+                    <el-table-column :label="$t('commons.login.username')" prop="username" />
+                    <el-table-column :label="$t('commons.login.password')" prop="password">
+                        <template #default="{ row }">
+                            <div>
+                                <span style="float: left; line-height: 25px" v-if="!row.showPassword">***********</span>
+                                <div style="cursor: pointer; float: left" v-if="!row.showPassword">
+                                    <el-icon
+                                        style="margin-left: 5px; margin-top: 3px"
+                                        @click="row.showPassword = true"
+                                        :size="16"
+                                    >
+                                        <View />
+                                    </el-icon>
+                                </div>
+                                <span style="float: left" v-if="row.showPassword">{{ row.password }}</span>
+                                <div style="cursor: pointer; float: left" v-if="row.showPassword">
+                                    <el-icon
+                                        style="margin-left: 5px; margin-top: 3px"
+                                        @click="row.showPassword = false"
+                                        :size="16"
+                                    >
+                                        <Hide />
+                                    </el-icon>
+                                </div>
+                                <div style="cursor: pointer; float: left">
+                                    <el-icon style="margin-left: 5px; margin-top: 3px" :size="16" @click="onCopy(row)">
+                                        <DocumentCopy />
+                                    </el-icon>
+                                </div>
+                            </div>
+                        </template>
+                    </el-table-column>
+                    <el-table-column
+                        prop="description"
+                        :label="$t('commons.table.description')"
+                        show-overflow-tooltip
+                    />
+                    <el-table-column
+                        prop="createdAt"
+                        :label="$t('commons.table.date')"
+                        :formatter="dateFormat"
+                        show-overflow-tooltip
+                    />
+                    <fu-table-operations
+                        width="370px"
+                        :buttons="buttons"
+                        :ellipsis="10"
+                        :label="$t('commons.table.operate')"
+                        fix
+                    />
+                </ComplexTable>
+            </template>
+        </LayoutContent>
 
-        <ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit"></ConfirmDialog>
-
-        <template #footer>
-            <span class="dialog-footer">
-                <el-button @click="dialogVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
-                <el-button type="primary" @click="onSave(formRef)">
-                    {{ $t('commons.button.confirm') }}
-                </el-button>
-            </span>
-        </template>
-    </el-drawer>
+        <OperateDialog ref="dialogRef" @search="search" />
+    </div>
 </template>
 
 <script lang="ts" setup>
-import { reactive, ref } from 'vue';
-import { Rules } from '@/global/form-rules';
+import { dateFormat } from '@/utils/util';
+import { onMounted, reactive, ref } from 'vue';
+import { deleteRemoteDB, searchRemoteDBs } from '@/api/modules/database';
+import OperateDialog from '@/views/database/mysql/remote/operate/index.vue';
 import i18n from '@/lang';
-import { ElForm } from 'element-plus';
-import { updateMysqlAccess } from '@/api/modules/database';
-import ConfirmDialog from '@/components/confirm-dialog/index.vue';
-import DrawerHeader from '@/components/drawer-header/index.vue';
-import { MsgSuccess } from '@/utils/message';
+import { MsgError, MsgSuccess } from '@/utils/message';
+import useClipboard from 'vue-clipboard3';
+import { Database } from '@/api/interface/database';
+import { useDeleteData } from '@/hooks/use-delete-data';
+const { toClipboard } = useClipboard();
 
 const loading = ref(false);
 
-const dialogVisiable = ref(false);
-const form = reactive({
-    privilege: false,
+const dialogRef = ref();
+
+const data = ref();
+const paginationConfig = reactive({
+    currentPage: 1,
+    pageSize: 10,
+    total: 0,
 });
+const searchName = ref();
 
-const confirmDialogRef = ref();
-
-type FormInstance = InstanceType<typeof ElForm>;
-const formRef = ref<FormInstance>();
-
-interface DialogProps {
-    privilege: boolean;
-}
-
-const acceptParams = (prop: DialogProps): void => {
-    form.privilege = prop.privilege;
-    dialogVisiable.value = true;
-};
-
-const handleClose = () => {
-    dialogVisiable.value = false;
-};
-
-const onSubmit = async () => {
-    let param = {
-        id: 0,
-        value: form.privilege ? '%' : 'localhost',
+const search = async (column?: any) => {
+    let params = {
+        page: paginationConfig.currentPage,
+        pageSize: paginationConfig.pageSize,
+        info: searchName.value,
+        type: 'mysql',
+        orderBy: column?.order ? column.prop : 'created_at',
+        order: column?.order ? column.order : 'null',
     };
-    loading.value = true;
-    await updateMysqlAccess(param)
-        .then(() => {
-            loading.value = false;
-            MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
-            dialogVisiable.value = false;
-        })
-        .catch(() => {
-            loading.value = false;
-        });
+    const res = await searchRemoteDBs(params);
+    data.value = res.data.items || [];
+    paginationConfig.total = res.data.total;
 };
 
-const onSave = async (formEl: FormInstance | undefined) => {
-    if (!formEl) return;
-    formEl.validate(async (valid) => {
-        if (!valid) return;
-        let params = {
-            header: i18n.global.t('database.confChange'),
-            operationInfo: i18n.global.t('database.restartNowHelper'),
-            submitInputInfo: i18n.global.t('database.restartNow'),
-        };
-        confirmDialogRef.value!.acceptParams(params);
-    });
+const onOpenDialog = async (
+    title: string,
+    rowData: Partial<Database.RemoteDBInfo> = {
+        name: '',
+        type: 'mysql',
+        version: '5.6.x',
+        address: '',
+        port: 3306,
+        username: '',
+        password: '',
+        description: '',
+    },
+) => {
+    let params = {
+        title,
+        rowData: { ...rowData },
+    };
+    dialogRef.value!.acceptParams(params);
 };
 
-defineExpose({
-    acceptParams,
+const onCopy = async (row: any) => {
+    try {
+        await toClipboard(row.password);
+        MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
+    } catch (e) {
+        MsgError(i18n.global.t('commons.msg.copyfailed'));
+    }
+};
+
+const onDelete = async (row: Database.RemoteDBInfo) => {
+    await useDeleteData(deleteRemoteDB, row.id, 'commons.msg.delete');
+    search();
+};
+
+const buttons = [
+    {
+        label: i18n.global.t('commons.button.edit'),
+        click: (row: Database.RemoteDBInfo) => {
+            onOpenDialog('edit', row);
+        },
+    },
+    {
+        label: i18n.global.t('commons.button.delete'),
+        click: (row: Database.RemoteDBInfo) => {
+            onDelete(row);
+        },
+    },
+];
+
+onMounted(() => {
+    search();
 });
 </script>
diff --git a/frontend/src/views/database/remote-db/operate/index.vue b/frontend/src/views/database/mysql/remote/operate/index.vue
similarity index 50%
rename from frontend/src/views/database/remote-db/operate/index.vue
rename to frontend/src/views/database/mysql/remote/operate/index.vue
index b5b8db0a2..5e28e272e 100644
--- a/frontend/src/views/database/remote-db/operate/index.vue
+++ b/frontend/src/views/database/mysql/remote/operate/index.vue
@@ -6,33 +6,33 @@
         <el-form ref="formRef" label-position="top" :model="dialogData.rowData" :rules="rules">
             <el-row type="flex" justify="center">
                 <el-col :span="22">
-                    <el-form-item :label="$t('cronjob.taskName')" prop="name">
-                        <el-input
-                            :disabled="dialogData.title === 'edit'"
-                            clearable
-                            v-model.trim="dialogData.rowData!.name"
-                        />
+                    <el-form-item :label="$t('commons.table.name')" prop="name">
+                        <el-input clearable v-model.trim="dialogData.rowData!.name" />
                     </el-form-item>
-                    <el-form-item :label="$t('cronjob.taskType')" prop="type">
-                        <el-select v-model="dialogData.rowData!.type">
-                            <el-option value="Mysql" label="Mysql" />
-                            <el-option value="Redis" label="Redis" />
+                    <el-form-item :label="$t('database.version')" prop="version">
+                        <el-select v-model="dialogData.rowData!.version">
+                            <el-option value="5.6.x" label="5.6.x" />
+                            <el-option value="5.7.x" label="5.7.x" />
+                            <el-option value="8.0.x" label="8.0.x" />
                         </el-select>
                     </el-form-item>
-
-                    <el-form-item :label="$t('cronjob.taskName')" prop="address">
+                    <el-form-item :label="$t('database.address')" prop="address">
                         <el-input clearable v-model.trim="dialogData.rowData!.address" />
                     </el-form-item>
-                    <el-form-item :label="$t('cronjob.taskName')" prop="port">
-                        <el-input clearable v-model.number="dialogData.rowData!.port" />
+                    <el-form-item :label="$t('commons.table.port')" prop="port">
+                        <el-input clearable v-model.trim="dialogData.rowData!.port" />
                     </el-form-item>
-                    <el-form-item :label="$t('cronjob.taskName')" prop="username">
+                    <el-form-item :label="$t('commons.login.username')" prop="username">
                         <el-input clearable v-model.trim="dialogData.rowData!.username" />
                     </el-form-item>
-                    <el-form-item :label="$t('cronjob.taskName')" prop="password">
-                        <el-input clearable v-model.trim="dialogData.rowData!.password" />
+                    <el-form-item :label="$t('commons.login.password')" prop="password">
+                        <el-input type="password" clearable show-password v-model.trim="dialogData.rowData!.password">
+                            <template #append>
+                                <el-button @click="random">{{ $t('commons.button.random') }}</el-button>
+                            </template>
+                        </el-input>
                     </el-form-item>
-                    <el-form-item :label="$t('cronjob.description')" prop="description">
+                    <el-form-item :label="$t('commons.table.description')" prop="description">
                         <el-input clearable v-model.trim="dialogData.rowData!.description" />
                     </el-form-item>
                 </el-col>
@@ -53,14 +53,16 @@
 import { reactive, ref } from 'vue';
 import i18n from '@/lang';
 import { ElForm } from 'element-plus';
-import { Cronjob } from '@/api/interface/cronjob';
-import { addCronjob, editCronjob } from '@/api/modules/cronjob';
+import { Database } from '@/api/interface/database';
 import DrawerHeader from '@/components/drawer-header/index.vue';
 import { MsgSuccess } from '@/utils/message';
+import { Rules } from '@/global/form-rules';
+import { getRandomStr } from '@/utils/util';
+import { addRemoteDB, editRemoteDB } from '@/api/modules/database';
 
 interface DialogProps {
     title: string;
-    rowData?: Cronjob.CronjobInfo;
+    rowData?: Database.RemoteDBInfo;
     getTableList?: () => Promise<any>;
 }
 const title = ref<string>('');
@@ -70,7 +72,7 @@ const dialogData = ref<DialogProps>({
 });
 const acceptParams = (params: DialogProps): void => {
     dialogData.value = params;
-    title.value = i18n.global.t('cronjob.' + dialogData.value.title);
+    title.value = i18n.global.t('database.' + dialogData.value.title + 'RemoteDB');
     drawerVisiable.value = true;
 };
 const emit = defineEmits<{ (e: 'search'): void }>();
@@ -81,23 +83,49 @@ const handleClose = () => {
 
 const rules = reactive({
     name: [Rules.requiredInput],
-    type: [Rules.requiredSelect],
-    address: [Rules.requiredInput],
+    version: [Rules.requiredSelect],
+    address: [Rules.ip],
     port: [Rules.port],
+    username: [Rules.requiredInput],
+    password: [Rules.requiredInput],
 });
 
 type FormInstance = InstanceType<typeof ElForm>;
 const formRef = ref<FormInstance>();
 
+const random = async () => {
+    dialogData.value.rowData!.password = getRandomStr(16);
+};
+
 const onSubmit = async (formEl: FormInstance | undefined) => {
     if (!formEl) return;
     formEl.validate(async (valid) => {
         if (!valid) return;
         if (dialogData.value.title === 'create') {
-            await addCronjob(dialogData.value.rowData);
+            let param = {
+                name: dialogData.value.rowData.name,
+                type: 'mysql',
+                version: dialogData.value.rowData.version,
+                from: 'remote',
+                address: dialogData.value.rowData.address,
+                port: dialogData.value.rowData.port,
+                username: dialogData.value.rowData.username,
+                password: dialogData.value.rowData.password,
+                description: dialogData.value.rowData.description,
+            };
+            await addRemoteDB(param);
         }
         if (dialogData.value.title === 'edit') {
-            await editCronjob(dialogData.value.rowData);
+            let param = {
+                id: dialogData.value.rowData.id,
+                version: dialogData.value.rowData.version,
+                address: dialogData.value.rowData.address,
+                port: dialogData.value.rowData.port,
+                username: dialogData.value.rowData.username,
+                password: dialogData.value.rowData.password,
+                description: dialogData.value.rowData.description,
+            };
+            await editRemoteDB(param);
         }
 
         MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
diff --git a/frontend/src/views/database/mysql/root-password/index.vue b/frontend/src/views/database/mysql/root-password/index.vue
index 7536e5aa3..cae9893f7 100644
--- a/frontend/src/views/database/mysql/root-password/index.vue
+++ b/frontend/src/views/database/mysql/root-password/index.vue
@@ -6,22 +6,6 @@
         <el-form @submit.prevent v-loading="loading" ref="formRef" :model="form" label-position="top">
             <el-row type="flex" justify="center">
                 <el-col :span="22">
-                    <el-form-item :label="$t('database.rootPassword')" :rules="Rules.requiredInput" prop="password">
-                        <el-input type="password" show-password clearable v-model="form.password">
-                            <template #append>
-                                <el-button @click="onCopy(form.password)">{{ $t('commons.button.copy') }}</el-button>
-                                <el-divider direction="vertical" />
-                                <el-button @click="random">
-                                    {{ $t('commons.button.random') }}
-                                </el-button>
-                            </template>
-                        </el-input>
-                    </el-form-item>
-                    <el-form-item :label="$t('database.serviceName')" prop="serviceName">
-                        <el-tag>{{ form.serviceName }}</el-tag>
-                        <el-button @click="onCopy(form.serviceName)" icon="DocumentCopy" link></el-button>
-                        <span class="input-help">{{ $t('database.serviceNameHelper') }}</span>
-                    </el-form-item>
                     <el-form-item :label="$t('database.containerConn')">
                         <el-tag>
                             {{ form.serviceName + ':3306' }}
@@ -35,11 +19,30 @@
                         <el-tag>{{ $t('database.localIP') + ':' + form.port }}</el-tag>
                         <span class="input-help">{{ $t('database.remoteConnHelper2') }}</span>
                     </el-form-item>
+
+                    <el-divider border-style="dashed" />
+
+                    <el-form-item :label="$t('database.remoteAccess')" prop="privilege">
+                        <el-switch v-model="form.privilege" @change="onSaveAccess" />
+                        <span class="input-help">{{ $t('database.remoteConnHelper') }}</span>
+                    </el-form-item>
+                    <el-form-item :label="$t('database.rootPassword')" :rules="Rules.requiredInput" prop="password">
+                        <el-input type="password" show-password clearable v-model="form.password">
+                            <template #append>
+                                <el-button @click="onCopy(form.password)">{{ $t('commons.button.copy') }}</el-button>
+                                <el-divider direction="vertical" />
+                                <el-button @click="random">
+                                    {{ $t('commons.button.random') }}
+                                </el-button>
+                            </template>
+                        </el-input>
+                    </el-form-item>
                 </el-col>
             </el-row>
         </el-form>
 
-        <ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit"></ConfirmDialog>
+        <ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit" @cancel="loadPassword"></ConfirmDialog>
+        <ConfirmDialog ref="confirmAccessDialogRef" @confirm="onSubmitAccess" @cancel="loadAccess"></ConfirmDialog>
 
         <template #footer>
             <span class="dialog-footer">
@@ -59,7 +62,7 @@ import { ref } from 'vue';
 import { Rules } from '@/global/form-rules';
 import i18n from '@/lang';
 import { ElForm } from 'element-plus';
-import { updateMysqlPassword } from '@/api/modules/database';
+import { loadRemoteAccess, updateMysqlAccess, updateMysqlPassword } from '@/api/modules/database';
 import ConfirmDialog from '@/components/confirm-dialog/index.vue';
 import { GetAppConnInfo } from '@/api/modules/app';
 import DrawerHeader from '@/components/drawer-header/index.vue';
@@ -75,10 +78,12 @@ const dialogVisiable = ref(false);
 const form = ref<App.DatabaseConnInfo>({
     password: '',
     serviceName: '',
+    privilege: false,
     port: 0,
 });
 
 const confirmDialogRef = ref();
+const confirmAccessDialogRef = ref();
 
 type FormInstance = InstanceType<typeof ElForm>;
 const formRef = ref<FormInstance>();
@@ -86,6 +91,7 @@ const formRef = ref<FormInstance>();
 const acceptParams = (): void => {
     form.value.password = '';
     loadPassword();
+    loadAccess();
     dialogVisiable.value = true;
 };
 
@@ -106,6 +112,11 @@ const handleClose = () => {
     dialogVisiable.value = false;
 };
 
+const loadAccess = async () => {
+    const res = await loadRemoteAccess();
+    form.value.privilege = res.data;
+};
+
 const loadPassword = async () => {
     const res = await GetAppConnInfo('mysql');
     form.value = res.data;
@@ -141,6 +152,32 @@ const onSave = async (formEl: FormInstance | undefined) => {
     });
 };
 
+const onSubmitAccess = async () => {
+    let param = {
+        id: 0,
+        value: form.value.privilege ? '%' : 'localhost',
+    };
+    loading.value = true;
+    await updateMysqlAccess(param)
+        .then(() => {
+            loading.value = false;
+            MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
+            dialogVisiable.value = false;
+        })
+        .catch(() => {
+            loading.value = false;
+        });
+};
+
+const onSaveAccess = () => {
+    let params = {
+        header: i18n.global.t('database.confChange'),
+        operationInfo: i18n.global.t('database.restartNowHelper'),
+        submitInputInfo: i18n.global.t('database.restartNow'),
+    };
+    confirmAccessDialogRef.value!.acceptParams(params);
+};
+
 defineExpose({
     acceptParams,
 });
diff --git a/frontend/src/views/database/remote-db/index.vue b/frontend/src/views/database/remote-db/index.vue
deleted file mode 100644
index 77c3a6c6a..000000000
--- a/frontend/src/views/database/remote-db/index.vue
+++ /dev/null
@@ -1,152 +0,0 @@
-<template>
-    <div v-loading="loading">
-        <LayoutContent :title="'MySQL ' + $t('menu.database')">
-            <template #toolbar>
-                <el-row>
-                    <el-col :xs="24" :sm="20" :md="20" :lg="20" :xl="20">
-                        <el-button type="primary" @click="onOpenDialog('create')">
-                            {{ $t('database.create') }}
-                        </el-button>
-                    </el-col>
-                    <el-col :xs="24" :sm="4" :md="4" :lg="4" :xl="4">
-                        <div class="search-button">
-                            <el-input
-                                v-model="searchName"
-                                clearable
-                                @clear="search()"
-                                suffix-icon="Search"
-                                @keyup.enter="search()"
-                                @change="search()"
-                                :placeholder="$t('commons.button.search')"
-                            ></el-input>
-                        </div>
-                    </el-col>
-                </el-row>
-            </template>
-            <template #main>
-                <ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data">
-                    <el-table-column :label="$t('commons.table.name')" prop="name" sortable />
-                    <el-table-column :label="$t('commons.login.username')" prop="address" />
-                    <el-table-column :label="$t('commons.login.username')" prop="username" />
-                    <el-table-column :label="$t('commons.login.password')" prop="password">
-                        <template #default="{ row }">
-                            <div>
-                                <span style="float: left; line-height: 25px" v-if="!row.showPassword">***********</span>
-                                <div style="cursor: pointer; float: left" v-if="!row.showPassword">
-                                    <el-icon
-                                        style="margin-left: 5px; margin-top: 3px"
-                                        @click="row.showPassword = true"
-                                        :size="16"
-                                    >
-                                        <View />
-                                    </el-icon>
-                                </div>
-                                <span style="float: left" v-if="row.showPassword">{{ row.password }}</span>
-                                <div style="cursor: pointer; float: left" v-if="row.showPassword">
-                                    <el-icon
-                                        style="margin-left: 5px; margin-top: 3px"
-                                        @click="row.showPassword = false"
-                                        :size="16"
-                                    >
-                                        <Hide />
-                                    </el-icon>
-                                </div>
-                                <div style="cursor: pointer; float: left">
-                                    <el-icon style="margin-left: 5px; margin-top: 3px" :size="16" @click="onCopy(row)">
-                                        <DocumentCopy />
-                                    </el-icon>
-                                </div>
-                            </div>
-                        </template>
-                    </el-table-column>
-                    <el-table-column
-                        prop="createdAt"
-                        :label="$t('commons.table.date')"
-                        :formatter="dateFormat"
-                        show-overflow-tooltip
-                    />
-                </ComplexTable>
-            </template>
-        </LayoutContent>
-
-        <OperateDialog ref="dialogRef" @search="search" />
-    </div>
-</template>
-
-<script lang="ts" setup>
-import { dateFormat } from '@/utils/util';
-import { reactive, ref } from 'vue';
-import { searchRemoteDBs } from '@/api/modules/database';
-import i18n from '@/lang';
-import { MsgError, MsgSuccess } from '@/utils/message';
-import useClipboard from 'vue-clipboard3';
-import { Database } from '@/api/interface/database';
-const { toClipboard } = useClipboard();
-
-const loading = ref(false);
-
-const dialogRef = ref();
-
-const data = ref();
-const paginationConfig = reactive({
-    currentPage: 1,
-    pageSize: 10,
-    total: 0,
-});
-const searchName = ref();
-
-const search = async (column?: any) => {
-    let params = {
-        page: paginationConfig.currentPage,
-        pageSize: paginationConfig.pageSize,
-        info: searchName.value,
-        orderBy: column?.order ? column.prop : 'created_at',
-        order: column?.order ? column.order : 'null',
-    };
-    const res = await searchRemoteDBs(params);
-    data.value = res.data.items || [];
-    paginationConfig.total = res.data.total;
-};
-
-const onOpenDialog = async (
-    title: string,
-    rowData: Partial<Database.RemoteDBInfo> = {
-        name: '',
-        type: 'Mysql',
-        address: '',
-        port: 3306,
-        username: '',
-        password: '',
-        description: '',
-    },
-) => {
-    let params = {
-        title,
-        rowData: { ...rowData },
-    };
-    dialogRef.value!.acceptParams(params);
-};
-
-const onCopy = async (row: any) => {
-    try {
-        await toClipboard(row.password);
-        MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
-    } catch (e) {
-        MsgError(i18n.global.t('commons.msg.copyfailed'));
-    }
-};
-
-// const onDelete = async (row: Database.MysqlDBInfo) => {
-//     const res = await deleteCheckMysqlDB(row.id);
-//     deleteRef.value.acceptParams({ id: row.id, name: row.name });
-// };
-
-// const buttons = [
-//     {
-//         label: i18n.global.t('commons.button.delete'),
-//         click: (row: Database.MysqlDBInfo) => {
-//             onDelete(row);
-//         },
-//     },
-// ];
-</script>