建安四年(公元199年)十二月,曹操自率軍屯於官渡(今河南中牟北),準備迎擊袁紹。
劉備在陶謙死後,曾一度出任徐州牧,後徐州被呂布攻占,劉備投奔曹操。曹操認為劉備是個英雄,先後表他為豫州牧、左將軍。曹操攻占徐州不久,淮南袁術準備逃往青州往依袁紹,曹操派劉備去截擊,袁術北上不得,嘔血而死。[]劉備到達下邳後,襲殺徐州刺史車胄,占據徐州,自己屯於小沛。曹操令劉岱、王忠率兵征討,被劉備擊敗。[]
建安五年(公元200年)正月,董承等人謀誅曹操,事泄被殺。曹操決定東征劉備。[]諸將皆說:“與您爭奪天下的人是袁紹,如今袁紹要來討戰,您卻棄之不顧,而要東征劉備,倘若袁紹乘機從背後進攻,該怎麼辦呢?”曹操說:“劉備是人傑,現在不除掉他,以後一定會成為心腹大患。袁紹雖然有遠大的誌向,但反應遲鈍,不會馬上出兵。”於是急速進軍,以迅雷不及掩耳之勢擊破劉備,劉備逃奔袁紹處。[
袁紹是當時北方最強大的一股勢力,也是曹操統一北方最強大的敵人。袁氏一門,自袁紹曾祖袁安以下,“四世居三公位”,“門生故吏遍於天下”,勢力本就很大,後袁紹取得冀、並、幽、青四州之地,實力大增,有軍隊數十萬人。袁紹以其長子袁譚、次子袁熙、外甥高乾分守青、幽、並三州,後方穩固,兵精糧足。他挑選精兵十萬、戰馬萬匹,誌在一舉消滅曹操。
建安五年(公元200年),袁紹命大將顏良等進兵白馬(今河南滑縣),自率大軍進屯黎陽(今河南浚縣東),向曹操發動進攻,拉開了大戰的序幕。曹操的實力比袁紹弱得多,曹操所占的黃河以南地區,是殘破不堪、尚未恢複生產的四戰之地,物資儲備也不如袁紹。其總兵力大概不過幾萬人,投入前線的兵力據《武帝紀》說“兵不滿萬,傷者十二三”。裴鬆之認為此數不準確,曹操的兵力不會如此之少,但曹操兵力遠遜於袁紹卻是毫無疑問的。
袁紹大軍來攻,許都震動。曹操安慰眾將,分析了袁紹的性格缺陷:“吾知紹之為人,誌大而智小,色厲而膽薄,忌克而少威”,雖然“兵多而分畫不明,將驕而眾令不一”,在這種情況下,袁紹地盤雖大,糧草雖足,但隻能是“為我奉也”。正是因為對袁紹有很深的認識,曹操才敢於在袁紹將要大軍壓境之時抽身去進攻劉備。
四月,曹操親自率兵北上解白馬之圍,他采納謀士荀攸之計,先進軍延津(今延津北一帶),做出要渡河襲擊袁軍的態勢,吸引袁軍分兵西向,然後突然轉向迅速趕往白馬。曹操軍突然殺到,袁軍措手不及,顏良被將軍關羽斬首[24],袁軍大敗,白馬之圍遂解。曹操救出白馬軍民,沿黃河西撤。袁紹聞知,立即命文醜、劉備渡河追趕曹操。曹操見追兵漸近,命軍士解鞍放馬,並置輜重於道。袁軍追兵大至,爭搶輜重,陣形混亂。曹操率領僅有的騎兵突然殺出,大破追兵,陣斬文醜。曹操初戰得勝,主動撤軍,繼續扼守官渡。[
八月,袁紹大軍連營而進,東西數十裡,依沙堆為屯,進逼官渡。曹操分兵堅守營壘,伺機而動。袁軍向曹營發動猛攻,先是作高櫓、起土山,由上向曹營中射箭,接著又挖地道,欲從地下襲擊曹營,皆被曹操以設投石機、挖掘溝壑之法破解。兩軍一攻一守,相持近二個月。久戰之下,曹操處境極為困難。
十月,袁紹從河北運來糧草萬餘車,派大將淳於瓊等帶萬餘人沿途護送,夜宿於離袁紹大營四十裡的烏巢。這時袁紹謀士許攸因向袁紹獻偷襲許都之計不成,且在河北的家眷犯法被抓,心生悔恨,而來投曹操,獻計讓曹操偷襲烏巢。曹操大喜,跣足出迎,之後親率精銳步騎五千人,軍隊人銜枚,馬勒口,打著袁軍旗幟,乘夜從小路偷襲烏巢。曹操軍至烏巢,命四麵放火,袁軍大亂,淳於瓊拒營死守。[]袁紹聞知,急忙派兵救援,曹操左右說:“賊騎稍近,請分兵拒之。”曹操大怒說:“賊在背後,乃白!”士卒都拚死力戰,因此大破袁軍,斬淳於瓊等,儘燔其糧草,袁紹派遣的援兵也戰敗而走。起初袁紹聽說曹操襲擊烏巢時,令張合、高覽率重兵圍攻曹軍營地。由於曹軍營地營壘堅固,烏巢先被攻破,張合、高覽等人聞訊率部投曹,袁軍潰散。袁紹與其子袁譚棄軍逃回黃河以北,曹軍大獲全勝。剩餘的袁軍假降,曹操將他們坑殺。曹軍前後斬首七萬餘級,儘獲袁軍輜重圖書珍寶。曹操清點袁紹書信,得到自己部下勾結袁紹的信,儘燒之,說:“當袁紹強大時,孤尚且不能自保,何況眾人呢!”官渡之戰後,冀州諸郡皆舉城歸順曹操。
在客觀上說,官渡之戰中的曹操處於劣勢,但由於他能正確分析客觀條件,善於聽取正確意見,所以能揚長避短,采用正確的戰略戰術,使戰爭向有利於自己的方麵轉化,經過自己主觀上的努力,終於贏得了勝利。此戰之後,曹操擊潰了最大的敵人袁紹,由他統一北方已是大勢所趨。
建安六年(公元201年)四月,曹操揚兵於黃河邊,擊破袁紹在倉亭的駐軍。袁紹在官渡之敗後,收合部隊,平定了反叛的諸郡縣。九月,曹操回到許縣。又南征在汝南的劉備、龔都,劉備投奔劉表,龔都等人皆逃散。
建安七年(公元202年)正月,曹操駐軍譙縣。又到達浚儀縣,治理睢陽渠,又派使者祭祀已故的太尉橋玄。然後,曹操進軍官渡。[]
五月,袁紹病死[],袁紹之子袁尚繼位,袁譚屯兵黎陽。九月,曹操親自北征,大戰於黎陽,袁譚、袁尚多次戰敗。
建安八年(公元203年)三月,曹操大破黎陽,袁譚、袁尚逃回鄴城。四月,曹操進軍鄴城。五月,曹操引軍退還,留賈信守黎陽。[]不久後,曹操引兵向南,征討劉表,袁譚、袁尚反目成仇,互相攻擊,袁譚不敵袁尚,敗走平原,遣辛毗向曹操乞降求救。當時諸將都懷疑有詐,隻有荀攸勸曹操答應袁譚,曹操說:“我攻打呂布之時,劉表沒有侵犯我方;官渡之戰時,他又不肯幫助袁紹。這隻是個自守的賊子,應該等到以後再來對付他。而袁譚、袁尚狡猾,我正應該趁北方混亂時發動攻擊。就算袁譚挾詐,不肯真心屈服我軍,但我擊破袁尚,奪取他的地盤,對我軍也更加有利。”於是再次北上,袁尚聞訊也退回鄴城。當時,袁尚部將呂曠、呂翔背叛袁尚,率眾投降曹操,曹操封兩人為列侯。[]袁譚私自刻將軍印綬,交給呂曠兩人,呂曠把將軍印送給曹操,曹操說:“我自然知道袁譚會耍些小聰明。他想讓我攻擊袁尚,然後趁機略民聚眾,自以為破袁尚後,實力足以自強,可趁我軍疲敝來與我抗衡。但擊破袁尚後,我的勢力更加強盛,哪可能會疲敝,讓他有機可乘呢?”[305]曹操為了讓袁譚暫時安心,還和袁譚結親,讓自己的兒子曹整娶袁譚的女兒。
建安九年(公元204年)正月,曹操率兵渡過黃河,截斷淇水,引入白溝,作為運糧的通道。二月,袁尚再次出兵攻打袁譚,曹操趁機進軍鄴城。當時蘇由、審配鎮守鄴城,曹操進軍到洹水時,蘇由投降。曹操到達鄴城外,做土山、地道。當時武安長尹楷屯毛城,通上黨糧道。四月,曹操留曹洪攻打鄴城,親自擊破尹楷。又擊破邯鄲的沮鵠。易陽令韓範、涉長梁岐皆舉縣投降。五月,曹操毀土山、地道,作圍塹,決漳水灌城,城中餓死者過半。七月,袁尚率軍回救,依滏水(今滏陽河)為營,曹操進軍將其營寨包圍。袁尚害怕,請求投降,曹操不許。袁尚乘夜逃跑,袁軍潰散。袁尚逃奔中山(今河北定縣)。曹操命人拿著繳獲袁尚的印綬節鉞招降鄴城守軍,城中鬥誌崩潰。八月,審配的侄子審榮打開東城門,曹操軍一舉攻破鄴城,擒殺審配。之後,曹操哭祭袁紹墓,慰勞袁紹妻子,將袁紹的家人和寶物都還給了袁家,並賜給他們雜繒絮,供養他們家。[]從這一年起,曹操把自己的據點北遷到了冀州的鄴城,政令軍隊此後皆從此出,而許縣則隻留些許官吏。
九月,曹操下令:“河北遭受袁氏之難,不用再上繳今年租賦!”又嚴厲打壓豪強兼並,百姓喜悅。曹操領冀州牧,並上表讓還兗州牧。當初,曹操圍攻鄴城時,袁譚趁機攻取甘陵、安平、勃海、河間,又擊破故安的袁尚敗軍,兼並其眾。曹操寫信給袁譚,責備他負約,與他斷絕婚姻,將他的女兒送回,然後進兵。十二月,曹操進入平原,略定諸縣。
建安十年(公元205年)正月,曹操攻滅袁譚,冀、青二州平定。當初袁尚兵敗後,投奔幽州刺史袁熙。此月,幽州大將焦觸、張南起兵反袁氏,袁尚、袁熙又逃奔三郡烏桓。焦觸自稱幽州刺史,舉郡縣歸附曹操。[]四月,黑山軍首領張燕率領其部眾十餘萬人投降曹操。[]故安人趙犢、霍奴起兵,殺死幽州刺史,三郡烏桓又圍攻鮮於輔於獷平。八月,曹操率兵北征,斬殺趙犢,又渡河救援獷平,烏桓奔走出塞。
當初,袁紹令其外甥高乾領並州。曹操攻破鄴城後,高乾投降了曹操,仍然被任命為並州刺史。而曹操討伐烏丸之時,高乾舉州反曹操,捉拿上黨太守,舉兵守壺口關。曹操遣樂進、李典討伐高乾,高乾退守壺關城。