diff --git a/CHANGELOG.md b/CHANGELOG.md
index b430e18ed6583..b979e34a5a3be 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ The order and collapsed state of columns is now persisted across page navigation
 
 ### Bug fixes and improvements
 
+- cli: clean up migration files created during a failed migrate api (close #4312) (#4319)
 - cli: add support for multiple versions of plugin (close #4105)
 - cli: template assets path in console HTML for unversioned builds
 - console: allow customising graphql field names for columns of views (close #3689) (#4255)
diff --git a/cli/migrate/api/migrate.go b/cli/migrate/api/migrate.go
index 4239bd80b7b75..29d601bebc6bf 100644
--- a/cli/migrate/api/migrate.go
+++ b/cli/migrate/api/migrate.go
@@ -84,9 +84,10 @@ func MigrateAPI(c *gin.Context) {
 		c.JSON(http.StatusOK, status)
 	case "POST":
 		var request Request
+		var err error
 
 		// Bind Request body to Request struct
-		if err := c.BindJSON(&request); err != nil {
+		if err = c.BindJSON(&request); err != nil {
 			c.JSON(http.StatusInternalServerError, &Response{Code: "request_parse_error", Message: err.Error()})
 			return
 		}
@@ -135,14 +136,14 @@ func MigrateAPI(c *gin.Context) {
 			}
 
 			if sqlUp.String() != "" {
-				err := createOptions.SetSQLUp(sqlUp.String())
+				err = createOptions.SetSQLUp(sqlUp.String())
 				if err != nil {
 					c.JSON(http.StatusInternalServerError, &Response{Code: "create_file_error", Message: err.Error()})
 					return
 				}
 			}
 			if sqlDown.String() != "" {
-				err := createOptions.SetSQLDown(sqlDown.String())
+				err = createOptions.SetSQLDown(sqlDown.String())
 				if err != nil {
 					c.JSON(http.StatusInternalServerError, &Response{Code: "create_file_error", Message: err.Error()})
 					return
@@ -150,25 +151,16 @@ func MigrateAPI(c *gin.Context) {
 			}
 
 			if sqlUp.String() != "" || sqlDown.String() != "" {
-				err := createOptions.Create()
+				err = createOptions.Create()
 				if err != nil {
 					c.JSON(http.StatusInternalServerError, &Response{Code: "create_file_error", Message: err.Error()})
 					return
 				}
-
-				defer func() {
-					if err != nil {
-						err := createOptions.Delete()
-						if err != nil {
-							logger.Debug(err)
-						}
-					}
-				}()
 			} else {
 				timestamp = 0
 			}
 		} else {
-			err := createOptions.SetMetaUp(request.Up)
+			err = createOptions.SetMetaUp(request.Up)
 			if err != nil {
 				c.JSON(http.StatusInternalServerError, &Response{Code: "create_file_error", Message: err.Error()})
 				return
@@ -184,19 +176,19 @@ func MigrateAPI(c *gin.Context) {
 				c.JSON(http.StatusInternalServerError, &Response{Code: "create_file_error", Message: err.Error()})
 				return
 			}
+		}
 
-			defer func() {
+		defer func() {
+			if err != nil && timestamp != 0 {
+				err := createOptions.Delete()
 				if err != nil {
-					err = createOptions.Delete()
-					if err != nil {
-						logger.Debug(err)
-					}
+					logger.Debug(err)
 				}
-			}()
-		}
+			}
+		}()
 
 		// Rescan file system
-		err := t.ReScan()
+		err = t.ReScan()
 		if err != nil {
 			c.JSON(http.StatusInternalServerError, &Response{Code: "internal_error", Message: err.Error()})
 			return