建安四年(公元199年)十二月,曹操自率军屯于官渡(今河南中牟北),准备迎击袁绍。
刘备在陶谦死后,曾一度出任徐州牧,后徐州被吕布攻占,刘备投奔曹操。曹操认为刘备是个英雄,先后表他为豫州牧、左将军。曹操攻占徐州不久,淮南袁术准备逃往青州往依袁绍,曹操派刘备去截击,袁术北上不得,呕血而死。[] 刘备到达下邳后,袭杀徐州刺史车胄,占据徐州,自己屯于小沛。曹操令刘岱、王忠率兵征讨,被刘备击败。[]
建安五年(公元200年)正月,董承等人谋诛曹操,事泄被杀。曹操决定东征刘备。[] 诸将皆说:“与您争夺天下的人是袁绍,如今袁绍要来讨战,您却弃之不顾,而要东征刘备,倘若袁绍乘机从背后进攻,该怎么办呢?”曹操说:“刘备是人杰,现在不除掉他,以后一定会成为心腹大患。袁绍虽然有远大的志向,但反应迟钝,不会马上出兵。”于是急速进军,以迅雷不及掩耳之势击破刘备,刘备逃奔袁绍处。[
袁绍是当时北方最强大的一股势力,也是曹操统一北方最强大的敌人。袁氏一门,自袁绍曾祖袁安以下,“四世居三公位”,“门生故吏遍于天下”,势力本就很大,后袁绍取得冀、并、幽、青四州之地,实力大增,有军队数十万人。袁绍以其长子袁谭、次子袁熙、外甥高干分守青、幽、并三州,后方稳固,兵精粮足。他挑选精兵十万、战马万匹,志在一举消灭曹操。
建安五年(公元200年),袁绍命大将颜良等进兵白马(今河南滑县),自率大军进屯黎阳(今河南浚县东),向曹操发动进攻,拉开了大战的序幕。曹操的实力比袁绍弱得多,曹操所占的黄河以南地区,是残破不堪、尚未恢复生产的四战之地,物资储备也不如袁绍。其总兵力大概不过几万人,投入前线的兵力据《武帝纪》说“兵不满万,伤者十二三”。裴松之认为此数不准确,曹操的兵力不会如此之少,但曹操兵力远逊于袁绍却是毫无疑问的。
袁绍大军来攻,许都震动。曹操安慰众将,分析了袁绍的性格缺陷:“吾知绍之为人,志大而智小,色厉而胆薄,忌克而少威”,虽然“兵多而分画不明,将骄而众令不一”,在这种情况下,袁绍地盘虽大,粮草虽足,但只能是“为我奉也”。正是因为对袁绍有很深的认识,曹操才敢于在袁绍将要大军压境之时抽身去进攻刘备。
四月,曹操亲自率兵北上解白马之围,他采纳谋士荀攸之计,先进军延津(今延津北一带),做出要渡河袭击袁军的态势,吸引袁军分兵西向,然后突然转向迅速赶往白马。曹操军突然杀到,袁军措手不及,颜良被将军关羽斩首[24] ,袁军大败,白马之围遂解。曹操救出白马军民,沿黄河西撤。袁绍闻知,立即命文丑、刘备渡河追赶曹操。曹操见追兵渐近,命军士解鞍放马,并置辎重于道。袁军追兵大至,争抢辎重,阵形混乱。曹操率领仅有的骑兵突然杀出,大破追兵,阵斩文丑。曹操初战得胜,主动撤军,继续扼守官渡。[
八月,袁绍大军连营而进,东西数十里,依沙堆为屯,进逼官渡。曹操分兵坚守营垒,伺机而动。袁军向曹营发动猛攻,先是作高橹、起土山,由上向曹营中射箭,接着又挖地道,欲从地下袭击曹营,皆被曹操以设投石机、挖掘沟壑之法破解。两军一攻一守,相持近二个月。久战之下,曹操处境极为困难。
十月,袁绍从河北运来粮草万余车,派大将淳于琼等带万余人沿途护送,夜宿于离袁绍大营四十里的乌巢。这时袁绍谋士许攸因向袁绍献偷袭许都之计不成,且在河北的家眷犯法被抓,心生悔恨,而来投曹操,献计让曹操偷袭乌巢。曹操大喜,跣足出迎,之后亲率精锐步骑五千人,军队人衔枚,马勒口,打着袁军旗帜,乘夜从小路偷袭乌巢。曹操军至乌巢,命四面放火,袁军大乱,淳于琼拒营死守。[] 袁绍闻知,急忙派兵救援,曹操左右说:“贼骑稍近,请分兵拒之。”曹操大怒说:“贼在背后,乃白!”士卒都拼死力战,因此大破袁军,斩淳于琼等,尽燔其粮草,袁绍派遣的援兵也战败而走。起初袁绍听说曹操袭击乌巢时,令张合、高览率重兵围攻曹军营地。由于曹军营地营垒坚固,乌巢先被攻破,张合、高览等人闻讯率部投曹,袁军溃散。袁绍与其子袁谭弃军逃回黄河以北,曹军大获全胜。剩余的袁军假降,曹操将他们坑杀。曹军前后斩首七万余级,尽获袁军辎重图书珍宝。曹操清点袁绍书信,得到自己部下勾结袁绍的信,尽烧之,说:“当袁绍强大时,孤尚且不能自保,何况众人呢!”官渡之战后,冀州诸郡皆举城归顺曹操。
在客观上说,官渡之战中的曹操处于劣势,但由于他能正确分析客观条件,善于听取正确意见,所以能扬长避短,采用正确的战略战术,使战争向有利于自己的方面转化,经过自己主观上的努力,终于赢得了胜利。此战之后,曹操击溃了最大的敌人袁绍,由他统一北方已是大势所趋。
建安六年(公元201年)四月,曹操扬兵于黄河边,击破袁绍在仓亭的驻军。袁绍在官渡之败后,收合部队,平定了反叛的诸郡县。九月,曹操回到许县。又南征在汝南的刘备、龚都,刘备投奔刘表,龚都等人皆逃散。
建安七年(公元202年)正月,曹操驻军谯县。又到达浚仪县,治理睢阳渠,又派使者祭祀已故的太尉桥玄。然后,曹操进军官渡。[]
五月,袁绍病死[] ,袁绍之子袁尚继位,袁谭屯兵黎阳。九月,曹操亲自北征,大战于黎阳,袁谭、袁尚多次战败。
建安八年(公元203年)三月,曹操大破黎阳,袁谭、袁尚逃回邺城。四月,曹操进军邺城。五月,曹操引军退还,留贾信守黎阳。[] 不久后,曹操引兵向南,征讨刘表,袁谭、袁尚反目成仇,互相攻击,袁谭不敌袁尚,败走平原,遣辛毗向曹操乞降求救。当时诸将都怀疑有诈,只有荀攸劝曹操答应袁谭,曹操说:“我攻打吕布之时,刘表没有侵犯我方;官渡之战时,他又不肯帮助袁绍。这只是个自守的贼子,应该等到以后再来对付他。而袁谭、袁尚狡猾,我正应该趁北方混乱时发动攻击。就算袁谭挟诈,不肯真心屈服我军,但我击破袁尚,夺取他的地盘,对我军也更加有利。”于是再次北上,袁尚闻讯也退回邺城。当时,袁尚部将吕旷、吕翔背叛袁尚,率众投降曹操,曹操封两人为列侯。[] 袁谭私自刻将军印绶,交给吕旷两人,吕旷把将军印送给曹操,曹操说:“我自然知道袁谭会耍些小聪明。他想让我攻击袁尚,然后趁机略民聚众,自以为破袁尚后,实力足以自强,可趁我军疲敝来与我抗衡。但击破袁尚后,我的势力更加强盛,哪可能会疲敝,让他有机可乘呢?”[305] 曹操为了让袁谭暂时安心,还和袁谭结亲,让自己的儿子曹整娶袁谭的女儿。
建安九年(公元204年)正月,曹操率兵渡过黄河,截断淇水,引入白沟,作为运粮的通道。二月,袁尚再次出兵攻打袁谭,曹操趁机进军邺城。当时苏由、审配镇守邺城,曹操进军到洹水时,苏由投降。曹操到达邺城外,做土山、地道。当时武安长尹楷屯毛城,通上党粮道。四月,曹操留曹洪攻打邺城,亲自击破尹楷。又击破邯郸的沮鹄。易阳令韩范、涉长梁岐皆举县投降。五月,曹操毁土山、地道,作围堑,决漳水灌城,城中饿死者过半。七月,袁尚率军回救,依滏水(今滏阳河)为营,曹操进军将其营寨包围。袁尚害怕,请求投降,曹操不许。袁尚乘夜逃跑,袁军溃散。袁尚逃奔中山(今河北定县)。曹操命人拿着缴获袁尚的印绶节钺招降邺城守军,城中斗志崩溃。八月,审配的侄子审荣打开东城门,曹操军一举攻破邺城,擒杀审配。之后,曹操哭祭袁绍墓,慰劳袁绍妻子,将袁绍的家人和宝物都还给了袁家,并赐给他们杂缯絮,供养他们家。[] 从这一年起,曹操把自己的据点北迁到了冀州的邺城,政令军队此后皆从此出,而许县则只留些许官吏。
九月,曹操下令:“河北遭受袁氏之难,不用再上缴今年租赋!”又严厉打压豪强兼并,百姓喜悦。曹操领冀州牧,并上表让还兖州牧。当初,曹操围攻邺城时,袁谭趁机攻取甘陵、安平、勃海、河间,又击破故安的袁尚败军,兼并其众。曹操写信给袁谭,责备他负约,与他断绝婚姻,将他的女儿送回,然后进兵。十二月,曹操进入平原,略定诸县。
建安十年(公元205年)正月,曹操攻灭袁谭,冀、青二州平定。当初袁尚兵败后,投奔幽州刺史袁熙。此月,幽州大将焦触、张南起兵反袁氏,袁尚、袁熙又逃奔三郡乌桓。焦触自称幽州刺史,举郡县归附曹操。[] 四月,黑山军首领张燕率领其部众十余万人投降曹操。[] 故安人赵犊、霍奴起兵,杀死幽州刺史,三郡乌桓又围攻鲜于辅于犷平。八月,曹操率兵北征,斩杀赵犊,又渡河救援犷平,乌桓奔走出塞。
当初,袁绍令其外甥高干领并州。曹操攻破邺城后,高干投降了曹操,仍然被任命为并州刺史。而曹操讨伐乌丸之时,高干举州反曹操,捉拿上党太守,举兵守壶口关。曹操遣乐进、李典讨伐高干,高干退守壶关城。