
做開發(fā)這些年MySQL裝過不少次卸載的次數(shù)也著實不少。別覺得卸載是件小事——我見過太多人因為卸載不干凈導致重裝后端口沖突、密碼失效、數(shù)據(jù)目錄殘留一堆舊文件折騰一整天。尤其是Ubuntu系統(tǒng)apt的包管理和配置文件分散在好幾個目錄光靠一句sudo apt remove mysql-server根本清不干凈。這篇從完整卸載MySQL的實操流程講起把每一步背后的邏輯和踩過的坑一起說清楚照著走基本能一次清干凈。我對接得最多的場景無非這三種一是開發(fā)環(huán)境用亂了各種配置和臟數(shù)據(jù)堆在一起想推倒重來二是裝MySQL時圖省事選了系統(tǒng)默認版本后來發(fā)現(xiàn)跟項目不匹配需要換版本三是轉(zhuǎn)向MariaDB或PostgreSQL徹底把MySQL移出系統(tǒng)。不管哪種只要涉及數(shù)據(jù)備份都該排在第一位。這不是保守是經(jīng)驗。1. 卸載前先想清楚備份這件事不能跳過1.1 邏輯備份與配置文件備份很多人覺得我只是想卸個數(shù)據(jù)庫重裝就好了但重裝并不代表數(shù)據(jù)還在。MySQL的數(shù)據(jù)文件默認存放在/var/lib/mysql這個目錄在apt purge時通常不會被自動清除但你在深度清理殘留時會手動刪掉它。一旦刪除加上沒有備份那基本就是終局。我現(xiàn)實中就見過開發(fā)者在卸載時順手執(zhí)行了rm -rf /var/lib/mysql結(jié)果想起來庫里有一份沒導出的報表腳本整個人都懵了。先備份數(shù)據(jù)邏輯備份用mysqldump最穩(wěn)妥mysqldump -u root -p --all-databases --single-transaction --routines --triggers all_databases.sql參數(shù)含義拆開講一下--all-databases導出所有數(shù)據(jù)庫包括mysql系統(tǒng)庫和information_schema這類元數(shù)據(jù)表。--single-transaction針對InnoDB的一致性快照導出全程不加表鎖在線執(zhí)行不影響業(yè)務(wù)。如果你用的是MyISAM表居多這個參數(shù)意義不大但不會報錯。--routines和--triggers存儲過程、函數(shù)和觸發(fā)器。這兩個選項特別容易被漏掉恢復(fù)時才發(fā)現(xiàn)自定義函數(shù)全沒了而很多業(yè)務(wù)邏輯是靠存儲過程實現(xiàn)的。如果只備份業(yè)務(wù)庫把--all-databases換成具體庫名例如--databases order_db user_db。注意庫名之間用空格分隔。配置文件也別忘了。全局配置通常在/etc/mysql/個人配置散落在~/.my.cnf。如果你改過字符集、隔離級別、慢查詢閾值或者binlog保留天數(shù)卸載前先打包拷貝一份到工作目錄。軟件可以重裝但一堆參數(shù)重寫起來特別耗時拷貝兩分鐘的事真遇上需要對比舊參數(shù)的時候就知道值了。1.2 環(huán)境信息存檔執(zhí)行備份命令之后順手記錄當前版本和服務(wù)狀態(tài)mysql --version systemctl status mysql這兩條輸出在卸載前后做對照非常有用。我記過幾次mysql版本號后來在排查重裝后配置不生效問題時靠版本差異對比定位到是8.0和5.7的認證插件不兼容導致的。把版本和服務(wù)名寫進筆記里比直接開干更穩(wěn)妥。2. 停服務(wù)與確認運行狀態(tài)2.1 干凈停服的常規(guī)做法卸載第一步不是刪包而是先讓MySQL服務(wù)停下來。很多人直接執(zhí)行apt remove系統(tǒng)在卸載腳本里也會嘗試停服務(wù)但服務(wù)進程持有的文件句柄和socket文件在運行狀態(tài)下處理起來容易留尾巴。我的習慣是先手動停再進入刪除流程。Ubuntu上停止MySQL常規(guī)命令sudo systemctl stop mysql服務(wù)名不一定是mysql。有的發(fā)行版叫mysqld有的帶版本后綴。先查一下再操作systemctl list-unit-files | grep -i mysql這個輸出能看到有哪些unit文件存在以及當前自啟狀態(tài)。然后執(zhí)行systemctl status mysql只要出現(xiàn)inactive或dead服務(wù)就算停干凈了。如果停在activating轉(zhuǎn)圈也不用慌可能是長事務(wù)或慢查詢還沒結(jié)束等一會兒再看。2.2 服務(wù)停不下來時的處理實際工作中偶爾會遇到服務(wù)停不下來的情況尤其是系統(tǒng)里有監(jiān)控腳本反復(fù)拉起服務(wù)或者客戶端連接池還在不斷建連。systemd停服務(wù)后連接全部斷掉服務(wù)才會真正退出。這時候用進程視角檢查ps -ef | grep mysqld | grep -v grep確認是殘留的守護進程還是連接導致的再決定下一步。如果確定要強制結(jié)束可以用kill命令。但這是應(yīng)急手段正常路徑不推薦。我處理這類問題時的原則是先看誰在占用再考慮強殺。一個找不到占用者的進程強殺之后可能會讓數(shù)據(jù)文件處于不一致狀態(tài)后續(xù)清理時會多出不少麻煩。停服務(wù)之后我會順手關(guān)掉開機自啟sudo systemctl disable mysql這一步看似冗余實際很關(guān)鍵。我有一次在卸載過程中因為某種原因服務(wù)被延遲啟動的定時任務(wù)重新拉起來了導致purge過程中提示文件被占用。先把自啟關(guān)掉能少踩這個坑。3. 用apt完成軟件包的一層層拆除3.1 remove和purge到底差在哪這里先明確一個概念apt remove和apt purge是兩回事。remove只刪除可執(zhí)行文件、庫文件、文檔這些內(nèi)容保留配置文件。也就是說執(zhí)行remove之后/etc/mysql/my.cnf還在舊密碼、舊socket配置一個不落。下次重裝時如果配置變了那就會彈出一堆讓你確認舊配置的界面甚至直接起不來。purge則會把配置文件一起清掉還會觸發(fā)postrm腳本把安裝時生成的臨時文件一并處理。我做卸載時一律用purge目的就是不想在下次重裝時夾帶一堆舊配置。3.2 核心包卸載命令與模擬演練卸載MySQL的三件套命令寫全sudo apt purge mysql-server mysql-client mysql-commonMySQL的包依賴關(guān)系有點像俄羅斯套娃。mysql-server是個meta包真正干活的是mysql-server-8.0這種帶版本號的包。你purge mysql-serverapt會自動把依賴它的版本包也標記為待刪除不需要手動逐個列名。不過強烈建議先跑一遍模擬看清楚刪除范圍sudo apt --simulate purge mysql-server mysql-client mysql-common模擬輸出會告訴你哪些包將被刪除、哪些自動安裝的依賴會變成孤兒包。重點看下列軟件包將被刪除那一段確認里面沒有誤傷其他項目依賴的包。比如你系統(tǒng)里有個應(yīng)用依賴libmysqlclient那purge時就要注意它會不會一起被拖下水。如果確認無誤把--simulate參數(shù)去掉再執(zhí)行。執(zhí)行purge時Ubuntu有時會彈出debconf界面詢問是否刪除MySQL配置文件。這里選擇是或刪除即可。如果apt卡在這個界面多半是終端顯示問題用Tab鍵切選項后回車就行。3.3 依賴清理與緩存清理包卸載完成后我習慣補上兩步清理sudo apt autoremove sudo apt cleanautoremove會把因為關(guān)聯(lián)MySQL而自動安裝、現(xiàn)在不再被任何包依賴的庫文件清理掉。這一步很多人漏掉系統(tǒng)里積了一堆無用的so文件時間久了磁盤占用自然就上去了。apt clean則是清空本地緩存的deb安裝包釋放/var/cache/apt/archives下的空間。如果你用的Ubuntu比較老可能見過sudo apt-get purge mysql*這種通配符寫法。當前20.04之后的版本不建議用通配符直接列包名更安全。用過通配符的人應(yīng)該都經(jīng)歷過系統(tǒng)把名字匹配mysql的所有包全切掉包括一些不相關(guān)的歷史遺留包。另外一個容易踩的坑如果系統(tǒng)里同時裝過MariaDB或者手動編譯過MySQL其他變種包名可能不完全一致。動手前用一條dpkg搜索先摸清底細dpkg -l | grep -i -E mysql|mariadb看到列表里有哪些包再決定怎么卸載比盲目復(fù)制網(wǎng)上的命令靠譜得多。4. 清理殘留目錄、配置、日志一個都別放過4.1 核心殘留目錄清單與處理apt purge執(zhí)行完之后系統(tǒng)層面的數(shù)據(jù)庫目錄、日志、運行時文件并不會自動刪除。原因不難理解Debian系包管理策略認為保留用戶數(shù)據(jù)是更安全的選擇。這也意味著如果你想徹底卸載這些目錄必須手動處理不能抱著purge就完了的心態(tài)。我整理了一張清理對照表每次操作都會對照著走路徑內(nèi)容說明處理方式/var/lib/mysql數(shù)據(jù)庫實體文件、ibdata1、undolog、binlogsudo rm -rf /var/lib/mysql/etc/mysql全局配置my.cnf及各子配置sudo rm -rf /etc/mysql/var/log/mysql錯誤日志、慢查詢?nèi)罩緎udo rm -rf /var/log/mysql/var/run/mysqldsocket文件、PID文件sudo rm -rf /var/run/mysqld想一次搞定直接用這一條sudo rm -rf /var/lib/mysql /etc/mysql /var/log/mysql /var/run/mysqld在使用這條命令之前務(wù)必再回頭確認一次備份文件確實存在于本機以外的地方至少不在這個命令的刪除范圍內(nèi)。我在一臺服務(wù)器上處理過一個問題那位開發(fā)者的備份文件就放在/var/lib/mysql旁邊的目錄他理所當然地以為不在刪除范圍內(nèi)結(jié)果腳本路徑寫錯了把整個家目錄刪了。慘痛教訓提一次記一次。刪除/var/lib/mysql時如果提示設(shè)備或資源忙說明有進程還在占用目錄內(nèi)文件句柄。先用sudo lsof D /var/lib/mysql查看占用進程處理完之后再執(zhí)行刪除。4.2 系統(tǒng)級殘留搜索與用戶清理目錄刪完后全盤再掃一遍find / -name *mysql* -type d 2/dev/null這個命令會有一定消耗多等幾秒正常。如果你只關(guān)心當前用戶的配置文件直接把范圍縮小就行l(wèi)s -la ~ | grep -i my重點看~/.my.cnf這是MySQL的客戶端默認配置文件里面可能殘留著舊連接的用戶名和端口。用戶目錄下一般不會有其他大文件殘留主要是socket文件出現(xiàn)在/tmp目錄的情況比較多看到了順手刪掉。還有一個容易被忽略的對象安裝時自動創(chuàng)建的mysql系統(tǒng)用戶和用戶組。大部分情況下保留這個用戶不影響后續(xù)使用但如果你追求完全純凈可以在確認沒有進程占用后處理掉sudo deluser mysql這里提醒一句某些備份工具或管理軟件會檢測mysql用戶的存在用來判斷系統(tǒng)是否具備MySQL能力。如果打算后續(xù)換用其他數(shù)據(jù)庫保留這個用戶反而能少一些依賴探測上的麻煩。所以這個操作屬于可選我一般建議保留除非系統(tǒng)里確實不需要任何mysql相關(guān)的身份標識。清理完這些再開一個新的終端窗口重新登錄一下讓shell的環(huán)境變量和二進制路徑緩存刷新。實測中新終端里的檢查結(jié)果比舊終端更可靠。5. 驗證卸載結(jié)果怎么確定真的干凈了5.1 狀態(tài)、文件、服務(wù)、端口四類驗證驗證階段是很多人偷懶的地方裝完瞥一眼沒報錯就算完事。但卸載這活兒驗證不到位重裝時分分鐘讓你頭疼。我把驗證流程固定成四步缺一不可。第一步查軟件包狀態(tài)dpkg -l | grep mysql正常情況這條命令沒有任何輸出。如果輸出中出現(xiàn)rc狀態(tài)說明包的配置文件仍在殘留。rc兩個字符分別代表期望狀態(tài)是移除、實際狀態(tài)是配置文件殘留。處理方式是再執(zhí)行一遍sudo dpkg -P 包名第二步查可執(zhí)行文件which mysql mysql --version正常情況下兩條命令都會提示找不到。如果which還能定位到/usr/bin/mysql說明二進制文件留在系統(tǒng)里要么是某個包沒清理干凈要么是當初手動安裝的跟apt無關(guān)。MySQL缺少時mysql這個命令不一定立刻消失因為shell有hash緩存。我都是新開終端再測避免舊終端的命令路徑引用干擾判斷。第三步查服務(wù)狀態(tài)systemctl status mysql正常情況輸出應(yīng)該是Unit mysql.service could not be found而不是inactive或dead。如果顯示后者說明服務(wù)配置文件還在packaging沒清完。第四步查端口監(jiān)聽ss -tlnp | grep 3306MySQL默認監(jiān)聽3306端口。卸載干凈后這個端口應(yīng)該空出來。如果還有進程在監(jiān)聽按下一節(jié)的排查思路處理。5.2 重裝驗證的終極大法前面四步都通過后我還會用最后一招在一個新終端里直接重新安裝一遍sudo apt install mysql-server如果安裝過程順利、初始化正常、沒有報目錄已存在或socket文件沖突說明之前的清理是徹底的。這個方法在開發(fā)機上成本很低但在生產(chǎn)服務(wù)器上可能有點興師動眾。對測試環(huán)境我每次都順手驗證一遍實測下來很穩(wěn)。6. 常見問題與排查實錄6.1 卸載后3306端口仍被占用這是最高頻的問題。先定位占用進程ss -tlnp | grep 3306常見原因是MySQL進程沒完全退出。用ps -ef | grep mysqld確認后處理。還有一種情況是socket文件殘留導致進程反復(fù)嘗試拉起檢查/var/run/mysqld目錄刪除后重啟一次系統(tǒng)就好。排除MySQL自身后還有一種可能系統(tǒng)里其他應(yīng)用比如Redis占用了3306端口。這屬于業(yè)務(wù)層沖突不是卸載遺留換個端口或改配置即可。6.2 dpkg提示軟件包狀態(tài)異常卸載過程中如果中斷過或者被強制終止dpkg的數(shù)據(jù)庫可能停留在半安裝狀態(tài)。此時先嘗試修復(fù)sudo dpkg --configure -a如果依然報錯需要強制移除異常狀態(tài)的包sudo dpkg --remove --force-remove-reinstreq 包名這條命令有破壞性執(zhí)行前務(wù)必備份/var/lib/dpkg/status文件值得用它來兜底。6.3 卸載時提示依賴關(guān)系錯誤這種問題大多發(fā)生在手動改過依賴或者用源碼方式裝過MySQL的情況下。apt會拒絕繼續(xù)刪除。處理方式是用apt的自動修復(fù)sudo apt --fix-broken install先把殘缺的依賴補齊或移除等apt狀態(tài)恢復(fù)正常再執(zhí)行purge。如果fix-broken無法定位具體問題去/var/log/apt/term.log翻日志找到阻塞的包名針對性處理。我遇到過某個庫里混著舊版本libmysqlclient就是靠這份日志鎖定的問題。6.4 卡在debconf交互界面purge時Ubuntu有時會彈出一個藍色界面問是否刪除配置文件。如果終端顯示不支持或字體太小看起來就像卡死。解決辦法是用Tab鍵切換選項回車確認。也可以用環(huán)境變量徹底禁用交互界面sudo DEBIAN_FRONTENDnoninteractive apt purge mysql-server mysql-client mysql-common非交互模式下這類界面不會彈出適合腳本化操作。不過要注意這種方式下如果安裝腳本需要確認某些參數(shù)它會直接用默認值可能不是你想要的結(jié)果。6.5 數(shù)據(jù)目錄無法刪除提示權(quán)限或設(shè)備或資源忙權(quán)限問題用sudo基本能解決。資源忙則說明有進程持有目錄內(nèi)文件句柄先用lsof定位占用進程sudo lsof D /var/lib/mysql找到PID后處理掉再執(zhí)行rm -rf就順暢了。如果確認完全沒有進程但目錄仍然刪不掉檢查文件系統(tǒng)是不是以只讀方式掛載。mount命令看一下掛載選項里面多一個ro字段就解釋了一切。6.6 apt自動更新干擾卸載流程Ubuntu的自動更新服務(wù)偶爾會和apt操作搶鎖表現(xiàn)為could not get lock報錯。通常等幾分鐘再執(zhí)行就好。如果確認沒有其他apt進程運行而鎖文件確實殘留可以手動清理sudo rm /var/lib/apt/lists/lock /var/lib/dpkg/lock這條命令要謹慎。鎖文件被真實占用時貿(mào)然刪除可能破壞正在進行的apt操作。先檢查一下進程列表里有沒有apt或dpkg相關(guān)進程確認無占用再用。寫在最后的一點點經(jīng)驗卸載MySQL這件事做成腳本也就十幾行命令但真正決定成敗的是執(zhí)行順序和驗證意識。備份永遠排第一purge比remove干凈/var/lib/mysql必須手動清最后一定要把驗證命令完整跑一遍。最后再分享一個小技巧如果是在開發(fā)環(huán)境反復(fù)折騰MySQL建議把數(shù)據(jù)目錄單獨掛到一個獨立路徑比如編譯安裝時指定--datadir/data/mysql或者通過my.cnf配置datadir指向獨立目錄。下次重裝時只需清掉軟件包數(shù)據(jù)目錄邊界清楚處理起來非常清晰也不會誤刪。把上面的思路梳理下來其實就是一句卸載不是刪除是一次需要留后手、留證據(jù)的系統(tǒng)操作。按流程走任何版本都能干干凈凈退場。