Haas, a former world number two but now down at 302, won 2-6, 7-6 (10/8), 6-4 for just his fourth victory in 17 meetings against his close friend.
Federer, building up for an assault on an eighth Wimbledon title, hadn't played since March, skipping the entire clay court season.
It was just the second defeat of 2017 for the 35-year-old, who claimed the Australian Open for his 18th major in January.
“I'm not so shocked to have lost. I knew I could lose against Tommy,” said Federer.
“He was so good at the end and if I am happy for anybody, then it's for Tommy.”
With a combined age of 74, it was the oldest match on the tour since 1982 as Haas, on a farewell to the sport in 2017, made his first quarterfinal since Rome in 2014.
“It's always special to play a close friend like Roger on grass, always lots of emotion,” said Haas, who has undergone nine surgeries in his career to mend a number of ailments.
“I saved a match point in the second set so was able to play more freely after that. I even shocked myself.”
Federer also held match point in his only other defeat this year to Russia's Evgeny Donskoy in Dubai.
Haas is the oldest player to beat a top five opponent since Jimmy Connors, at 39 years and five months old, defeated Michael Stich in Memphis in 1992.
He is also the lowest-ranked player to beat Federer since number 407 Bjorn Phau at Washington in 1999.
Federer, who fired 23 aces in the contest, had match point at 8-7 in the second set tie-breaker but hit a backhand long.
The German took his opportunity and converted his fourth set point when Federer double faulted for the first time in the match.
Haas controlled the decider, breaking for 3-1 before going on to take the victory on a second match point.
He will next face compatriot Mischa Zverev who beat qualifier and fellow German Yannick Hanfmann 7-6 (7/1), 6-2 in 83 minutes.
Philipp Kohlschreiber, the runner-up last year, advanced by beating Steve Johnson of the United States 7-6 (7/3), 5-7, 7-6 (10/8) in two hours and 39 minutes.
The 33-year-old Kohlschreiber, who lost to Austria's Dominic Thiem in the 2016 final, has won five of his seven career titles in Germany.